xref: /openbmc/linux/drivers/media/i2c/ov5640.c (revision f33b56d3)
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
5319a81c14SSteve Longerbeam #define OV5640_REG_CHIP_ID		0x300a
54f22996dbSHugues Fruchet #define OV5640_REG_IO_MIPI_CTRL00	0x300e
55f22996dbSHugues Fruchet #define OV5640_REG_PAD_OUTPUT_ENABLE01	0x3017
56f22996dbSHugues Fruchet #define OV5640_REG_PAD_OUTPUT_ENABLE02	0x3018
5719a81c14SSteve Longerbeam #define OV5640_REG_PAD_OUTPUT00		0x3019
58f22996dbSHugues Fruchet #define OV5640_REG_SYSTEM_CONTROL1	0x302e
5919a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL0		0x3034
6019a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL1		0x3035
6119a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL2		0x3036
6219a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL3		0x3037
6319a81c14SSteve Longerbeam #define OV5640_REG_SLAVE_ID		0x3100
64f22996dbSHugues Fruchet #define OV5640_REG_SCCB_SYS_CTRL1	0x3103
6519a81c14SSteve Longerbeam #define OV5640_REG_SYS_ROOT_DIVIDER	0x3108
6619a81c14SSteve Longerbeam #define OV5640_REG_AWB_R_GAIN		0x3400
6719a81c14SSteve Longerbeam #define OV5640_REG_AWB_G_GAIN		0x3402
6819a81c14SSteve Longerbeam #define OV5640_REG_AWB_B_GAIN		0x3404
6919a81c14SSteve Longerbeam #define OV5640_REG_AWB_MANUAL_CTRL	0x3406
7019a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_HI	0x3500
7119a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_MED	0x3501
7219a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_LO	0x3502
7319a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_MANUAL	0x3503
7419a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_REAL_GAIN	0x350a
7519a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_VTS		0x350c
763145efcdSJacopo Mondi #define OV5640_REG_TIMING_HS		0x3800
773145efcdSJacopo Mondi #define OV5640_REG_TIMING_VS		0x3802
783145efcdSJacopo Mondi #define OV5640_REG_TIMING_HW		0x3804
793145efcdSJacopo Mondi #define OV5640_REG_TIMING_VH		0x3806
8086633417SMaxime Ripard #define OV5640_REG_TIMING_DVPHO		0x3808
8186633417SMaxime Ripard #define OV5640_REG_TIMING_DVPVO		0x380a
8219a81c14SSteve Longerbeam #define OV5640_REG_TIMING_HTS		0x380c
8319a81c14SSteve Longerbeam #define OV5640_REG_TIMING_VTS		0x380e
843145efcdSJacopo Mondi #define OV5640_REG_TIMING_HOFFS		0x3810
853145efcdSJacopo Mondi #define OV5640_REG_TIMING_VOFFS		0x3812
86ce85705aSHugues Fruchet #define OV5640_REG_TIMING_TC_REG20	0x3820
8719a81c14SSteve Longerbeam #define OV5640_REG_TIMING_TC_REG21	0x3821
8819a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL00		0x3a00
8919a81c14SSteve Longerbeam #define OV5640_REG_AEC_B50_STEP		0x3a08
9019a81c14SSteve Longerbeam #define OV5640_REG_AEC_B60_STEP		0x3a0a
9119a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0D		0x3a0d
9219a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0E		0x3a0e
9319a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0F		0x3a0f
9419a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL10		0x3a10
9519a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL11		0x3a11
9619a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1B		0x3a1b
9719a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1E		0x3a1e
9819a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1F		0x3a1f
9919a81c14SSteve Longerbeam #define OV5640_REG_HZ5060_CTRL00	0x3c00
10019a81c14SSteve Longerbeam #define OV5640_REG_HZ5060_CTRL01	0x3c01
10119a81c14SSteve Longerbeam #define OV5640_REG_SIGMADELTA_CTRL0C	0x3c0c
10219a81c14SSteve Longerbeam #define OV5640_REG_FRAME_CTRL01		0x4202
103e3ee691dSHugues Fruchet #define OV5640_REG_FORMAT_CONTROL00	0x4300
1047cb013b1SChen-Yu Tsai #define OV5640_REG_VFIFO_HSIZE		0x4602
1057cb013b1SChen-Yu Tsai #define OV5640_REG_VFIFO_VSIZE		0x4604
1062b5c18f9SChen-Yu Tsai #define OV5640_REG_JPG_MODE_SELECT	0x4713
1074039b037SLad Prabhakar #define OV5640_REG_CCIR656_CTRL00	0x4730
108f22996dbSHugues Fruchet #define OV5640_REG_POLARITY_CTRL00	0x4740
10919a81c14SSteve Longerbeam #define OV5640_REG_MIPI_CTRL00		0x4800
11019a81c14SSteve Longerbeam #define OV5640_REG_DEBUG_MODE		0x4814
1116c957ed7SJacopo Mondi #define OV5640_REG_PCLK_PERIOD		0x4837
112e3ee691dSHugues Fruchet #define OV5640_REG_ISP_FORMAT_MUX_CTRL	0x501f
11319a81c14SSteve Longerbeam #define OV5640_REG_PRE_ISP_TEST_SET1	0x503d
11419a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL0		0x5580
11519a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL1		0x5581
11619a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL3		0x5583
11719a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL4		0x5584
11819a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL5		0x5585
11919a81c14SSteve Longerbeam #define OV5640_REG_AVG_READOUT		0x56a1
12019a81c14SSteve Longerbeam 
12119a81c14SSteve Longerbeam enum ov5640_mode_id {
12232ea5e05SHugues Fruchet 	OV5640_MODE_QQVGA_160_120 = 0,
12332ea5e05SHugues Fruchet 	OV5640_MODE_QCIF_176_144,
12419a81c14SSteve Longerbeam 	OV5640_MODE_QVGA_320_240,
12519a81c14SSteve Longerbeam 	OV5640_MODE_VGA_640_480,
12619a81c14SSteve Longerbeam 	OV5640_MODE_NTSC_720_480,
12719a81c14SSteve Longerbeam 	OV5640_MODE_PAL_720_576,
12819a81c14SSteve Longerbeam 	OV5640_MODE_XGA_1024_768,
12919a81c14SSteve Longerbeam 	OV5640_MODE_720P_1280_720,
13019a81c14SSteve Longerbeam 	OV5640_MODE_1080P_1920_1080,
13119a81c14SSteve Longerbeam 	OV5640_MODE_QSXGA_2592_1944,
13219a81c14SSteve Longerbeam 	OV5640_NUM_MODES,
13319a81c14SSteve Longerbeam };
13419a81c14SSteve Longerbeam 
13519a81c14SSteve Longerbeam enum ov5640_frame_rate {
13619a81c14SSteve Longerbeam 	OV5640_15_FPS = 0,
13719a81c14SSteve Longerbeam 	OV5640_30_FPS,
138e823fb16SMaxime Ripard 	OV5640_60_FPS,
13919a81c14SSteve Longerbeam 	OV5640_NUM_FRAMERATES,
14019a81c14SSteve Longerbeam };
14119a81c14SSteve Longerbeam 
14222845bf2SJacopo Mondi enum ov5640_pixel_rate_id {
14322845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_168M,
14422845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_148M,
14522845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_124M,
14622845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_96M,
14722845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_48M,
14822845bf2SJacopo Mondi 	OV5640_NUM_PIXEL_RATES,
14922845bf2SJacopo Mondi };
15022845bf2SJacopo Mondi 
15122845bf2SJacopo Mondi /*
15222845bf2SJacopo Mondi  * The chip manual suggests 24/48/96/192 MHz pixel clocks.
15322845bf2SJacopo Mondi  *
15422845bf2SJacopo Mondi  * 192MHz exceeds the sysclk limits; use 168MHz as maximum pixel rate for
15522845bf2SJacopo Mondi  * full resolution mode @15 FPS.
15622845bf2SJacopo Mondi  */
15722845bf2SJacopo Mondi static const u32 ov5640_pixel_rates[] = {
15822845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_168M] = 168000000,
15922845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_148M] = 148000000,
16022845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_124M] = 124000000,
16122845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_96M] = 96000000,
16222845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_48M] = 48000000,
16322845bf2SJacopo Mondi };
16422845bf2SJacopo Mondi 
1657a3b8d4bSJacopo Mondi /*
1667a3b8d4bSJacopo Mondi  * MIPI CSI-2 link frequencies.
1677a3b8d4bSJacopo Mondi  *
1687a3b8d4bSJacopo Mondi  * Derived from the above defined pixel rate for bpp = (8, 16, 24) and
1697a3b8d4bSJacopo Mondi  * data_lanes = (1, 2)
1707a3b8d4bSJacopo Mondi  *
1717a3b8d4bSJacopo Mondi  * link_freq = (pixel_rate * bpp) / (2 * data_lanes)
1727a3b8d4bSJacopo Mondi  */
1737a3b8d4bSJacopo Mondi static const s64 ov5640_csi2_link_freqs[] = {
1747a3b8d4bSJacopo Mondi 	992000000, 888000000, 768000000, 744000000, 672000000, 672000000,
1757a3b8d4bSJacopo Mondi 	592000000, 592000000, 576000000, 576000000, 496000000, 496000000,
1767a3b8d4bSJacopo Mondi 	384000000, 384000000, 384000000, 336000000, 296000000, 288000000,
1777a3b8d4bSJacopo Mondi 	248000000, 192000000, 192000000, 192000000, 96000000,
1787a3b8d4bSJacopo Mondi };
1797a3b8d4bSJacopo Mondi 
1807a3b8d4bSJacopo Mondi /* Link freq for default mode: UYVY 16 bpp, 2 data lanes. */
1817a3b8d4bSJacopo Mondi #define OV5640_DEFAULT_LINK_FREQ	13
1827a3b8d4bSJacopo Mondi 
183b7ed3abdSLoic Poulain enum ov5640_format_mux {
184b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_YUV422 = 0,
185b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_RGB,
186b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_DITHER,
187b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_RAW_DPC,
188b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_SNR_RAW,
189b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_RAW_CIP,
190b7ed3abdSLoic Poulain };
191b7ed3abdSLoic Poulain 
192a89f14bbSJacopo Mondi struct ov5640_pixfmt {
193e3ee691dSHugues Fruchet 	u32 code;
194e3ee691dSHugues Fruchet 	u32 colorspace;
1952d7671f6SJacopo Mondi 	u8 bpp;
196935fbc94SJacopo Mondi 	u8 ctrl00;
197935fbc94SJacopo Mondi 	enum ov5640_format_mux mux;
198a89f14bbSJacopo Mondi };
199a89f14bbSJacopo Mondi 
200a89f14bbSJacopo Mondi static const struct ov5640_pixfmt ov5640_dvp_formats[] = {
2012d7671f6SJacopo Mondi 	{
202935fbc94SJacopo Mondi 		/* YUV422, YUYV */
2032d7671f6SJacopo Mondi 		.code		= MEDIA_BUS_FMT_JPEG_1X8,
2042d7671f6SJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_JPEG,
2052d7671f6SJacopo Mondi 		.bpp		= 16,
206935fbc94SJacopo Mondi 		.ctrl00		= 0x30,
207935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_YUV422,
2082d7671f6SJacopo Mondi 	}, {
209935fbc94SJacopo Mondi 		/* YUV422, UYVY */
2102d7671f6SJacopo Mondi 		.code		= MEDIA_BUS_FMT_UYVY8_2X8,
2112d7671f6SJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
2122d7671f6SJacopo Mondi 		.bpp		= 16,
213935fbc94SJacopo Mondi 		.ctrl00		= 0x3f,
214935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_YUV422,
2152d7671f6SJacopo Mondi 	}, {
216935fbc94SJacopo Mondi 		/* YUV422, YUYV */
2172d7671f6SJacopo Mondi 		.code		= MEDIA_BUS_FMT_YUYV8_2X8,
2182d7671f6SJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
2192d7671f6SJacopo Mondi 		.bpp		= 16,
220935fbc94SJacopo Mondi 		.ctrl00		= 0x30,
221935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_YUV422,
2222d7671f6SJacopo Mondi 	}, {
223935fbc94SJacopo Mondi 		/* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */
2242d7671f6SJacopo Mondi 		.code		= MEDIA_BUS_FMT_RGB565_2X8_LE,
2252d7671f6SJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
2262d7671f6SJacopo Mondi 		.bpp		= 16,
227935fbc94SJacopo Mondi 		.ctrl00		= 0x6f,
228935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_RGB,
2292d7671f6SJacopo Mondi 	}, {
230935fbc94SJacopo Mondi 		/* RGB565 {r[4:0],g[5:3]},{g[2:0],b[4:0]} */
2312d7671f6SJacopo Mondi 		.code		= MEDIA_BUS_FMT_RGB565_2X8_BE,
2322d7671f6SJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
2332d7671f6SJacopo Mondi 		.bpp		= 16,
234935fbc94SJacopo Mondi 		.ctrl00		= 0x61,
235935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_RGB,
2362d7671f6SJacopo Mondi 	}, {
237935fbc94SJacopo Mondi 		/* Raw, BGBG... / GRGR... */
238a89f14bbSJacopo Mondi 		.code		= MEDIA_BUS_FMT_SBGGR8_1X8,
239a89f14bbSJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
240a89f14bbSJacopo Mondi 		.bpp		= 8,
241935fbc94SJacopo Mondi 		.ctrl00		= 0x00,
242935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_RAW_DPC,
243a89f14bbSJacopo Mondi 	}, {
244935fbc94SJacopo Mondi 		/* Raw bayer, GBGB... / RGRG... */
245a89f14bbSJacopo Mondi 		.code		= MEDIA_BUS_FMT_SGBRG8_1X8,
246a89f14bbSJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
247935fbc94SJacopo Mondi 		.bpp		= 8,
248935fbc94SJacopo Mondi 		.ctrl00		= 0x01,
249935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_RAW_DPC,
250a89f14bbSJacopo Mondi 	}, {
251935fbc94SJacopo Mondi 		/* Raw bayer, GRGR... / BGBG... */
252a89f14bbSJacopo Mondi 		.code		= MEDIA_BUS_FMT_SGRBG8_1X8,
253a89f14bbSJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
254a89f14bbSJacopo Mondi 		.bpp		= 8,
255935fbc94SJacopo Mondi 		.ctrl00		= 0x02,
256935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_RAW_DPC,
257a89f14bbSJacopo Mondi 	}, {
258935fbc94SJacopo Mondi 		/* Raw bayer, RGRG... / GBGB... */
259a89f14bbSJacopo Mondi 		.code		= MEDIA_BUS_FMT_SRGGB8_1X8,
260a89f14bbSJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
261a89f14bbSJacopo Mondi 		.bpp		= 8,
262935fbc94SJacopo Mondi 		.ctrl00		= 0x03,
263935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_RAW_DPC,
264a89f14bbSJacopo Mondi 	},
265a89f14bbSJacopo Mondi 	{ /* sentinel */ }
266a89f14bbSJacopo Mondi };
267a89f14bbSJacopo Mondi 
268a89f14bbSJacopo Mondi static const struct ov5640_pixfmt ov5640_csi2_formats[] = {
269a89f14bbSJacopo Mondi 	{
270935fbc94SJacopo Mondi 		/* YUV422, YUYV */
271a89f14bbSJacopo Mondi 		.code		= MEDIA_BUS_FMT_JPEG_1X8,
272a89f14bbSJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_JPEG,
273a89f14bbSJacopo Mondi 		.bpp		= 16,
274935fbc94SJacopo Mondi 		.ctrl00		= 0x30,
275935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_YUV422,
276a89f14bbSJacopo Mondi 	}, {
277935fbc94SJacopo Mondi 		/* YUV422, UYVY */
278a89f14bbSJacopo Mondi 		.code		= MEDIA_BUS_FMT_UYVY8_1X16,
279a89f14bbSJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
280a89f14bbSJacopo Mondi 		.bpp		= 16,
281935fbc94SJacopo Mondi 		.ctrl00		= 0x3f,
282935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_YUV422,
283a89f14bbSJacopo Mondi 	}, {
284935fbc94SJacopo Mondi 		/* YUV422, YUYV */
285a89f14bbSJacopo Mondi 		.code		= MEDIA_BUS_FMT_YUYV8_1X16,
286a89f14bbSJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
287a89f14bbSJacopo Mondi 		.bpp		= 16,
288935fbc94SJacopo Mondi 		.ctrl00		= 0x30,
289935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_YUV422,
290a89f14bbSJacopo Mondi 	}, {
291935fbc94SJacopo Mondi 		/* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */
2920a43fcd7SJacopo Mondi 		.code		= MEDIA_BUS_FMT_RGB565_1X16,
2930a43fcd7SJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
2940a43fcd7SJacopo Mondi 		.bpp		= 16,
295935fbc94SJacopo Mondi 		.ctrl00		= 0x6f,
296935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_RGB,
2970a43fcd7SJacopo Mondi 	}, {
298935fbc94SJacopo Mondi 		/* BGR888: RGB */
2996ac98b41SJacopo Mondi 		.code		= MEDIA_BUS_FMT_BGR888_1X24,
3006ac98b41SJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
3016ac98b41SJacopo Mondi 		.bpp		= 24,
302935fbc94SJacopo Mondi 		.ctrl00		= 0x23,
303935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_RGB,
3046ac98b41SJacopo Mondi 	}, {
305935fbc94SJacopo Mondi 		/* Raw, BGBG... / GRGR... */
3062d7671f6SJacopo Mondi 		.code		= MEDIA_BUS_FMT_SBGGR8_1X8,
3072d7671f6SJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
3082d7671f6SJacopo Mondi 		.bpp		= 8,
309935fbc94SJacopo Mondi 		.ctrl00		= 0x00,
310935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_RAW_DPC,
3112d7671f6SJacopo Mondi 	}, {
312935fbc94SJacopo Mondi 		/* Raw bayer, GBGB... / RGRG... */
3132d7671f6SJacopo Mondi 		.code		= MEDIA_BUS_FMT_SGBRG8_1X8,
3142d7671f6SJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
315935fbc94SJacopo Mondi 		.bpp		= 8,
316935fbc94SJacopo Mondi 		.ctrl00		= 0x01,
317935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_RAW_DPC,
3182d7671f6SJacopo Mondi 	}, {
319935fbc94SJacopo Mondi 		/* Raw bayer, GRGR... / BGBG... */
3202d7671f6SJacopo Mondi 		.code		= MEDIA_BUS_FMT_SGRBG8_1X8,
3212d7671f6SJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
3222d7671f6SJacopo Mondi 		.bpp		= 8,
323935fbc94SJacopo Mondi 		.ctrl00		= 0x02,
324935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_RAW_DPC,
3252d7671f6SJacopo Mondi 	}, {
326935fbc94SJacopo Mondi 		/* Raw bayer, RGRG... / GBGB... */
3272d7671f6SJacopo Mondi 		.code		= MEDIA_BUS_FMT_SRGGB8_1X8,
3282d7671f6SJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
3292d7671f6SJacopo Mondi 		.bpp		= 8,
330935fbc94SJacopo Mondi 		.ctrl00		= 0x03,
331935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_RAW_DPC,
3322d7671f6SJacopo Mondi 	},
333a89f14bbSJacopo Mondi 	{ /* sentinel */ }
334e3ee691dSHugues Fruchet };
335e3ee691dSHugues Fruchet 
33619a81c14SSteve Longerbeam /*
33719a81c14SSteve Longerbeam  * FIXME: remove this when a subdev API becomes available
33819a81c14SSteve Longerbeam  * to set the MIPI CSI-2 virtual channel.
33919a81c14SSteve Longerbeam  */
34019a81c14SSteve Longerbeam static unsigned int virtual_channel;
3418670d70aSHugues Fruchet module_param(virtual_channel, uint, 0444);
34219a81c14SSteve Longerbeam MODULE_PARM_DESC(virtual_channel,
34319a81c14SSteve Longerbeam 		 "MIPI CSI-2 virtual channel (0..3), default 0");
34419a81c14SSteve Longerbeam 
34519a81c14SSteve Longerbeam static const int ov5640_framerates[] = {
34619a81c14SSteve Longerbeam 	[OV5640_15_FPS] = 15,
34719a81c14SSteve Longerbeam 	[OV5640_30_FPS] = 30,
348e823fb16SMaxime Ripard 	[OV5640_60_FPS] = 60,
34919a81c14SSteve Longerbeam };
35019a81c14SSteve Longerbeam 
35119a81c14SSteve Longerbeam /* regulator supplies */
35219a81c14SSteve Longerbeam static const char * const ov5640_supply_name[] = {
35341d8d7f5SHugues Fruchet 	"DOVDD", /* Digital I/O (1.8V) supply */
35419a81c14SSteve Longerbeam 	"AVDD",  /* Analog (2.8V) supply */
35524c8ac89SFabio Estevam 	"DVDD",  /* Digital Core (1.5V) supply */
35619a81c14SSteve Longerbeam };
35719a81c14SSteve Longerbeam 
35819a81c14SSteve Longerbeam #define OV5640_NUM_SUPPLIES ARRAY_SIZE(ov5640_supply_name)
35919a81c14SSteve Longerbeam 
36019a81c14SSteve Longerbeam /*
36119a81c14SSteve Longerbeam  * Image size under 1280 * 960 are SUBSAMPLING
36219a81c14SSteve Longerbeam  * Image size upper 1280 * 960 are SCALING
36319a81c14SSteve Longerbeam  */
36419a81c14SSteve Longerbeam enum ov5640_downsize_mode {
36519a81c14SSteve Longerbeam 	SUBSAMPLING,
36619a81c14SSteve Longerbeam 	SCALING,
36719a81c14SSteve Longerbeam };
36819a81c14SSteve Longerbeam 
36919a81c14SSteve Longerbeam struct reg_value {
37019a81c14SSteve Longerbeam 	u16 reg_addr;
37119a81c14SSteve Longerbeam 	u8 val;
37219a81c14SSteve Longerbeam 	u8 mask;
37319a81c14SSteve Longerbeam 	u32 delay_ms;
37419a81c14SSteve Longerbeam };
37519a81c14SSteve Longerbeam 
3765113d5b3SJacopo Mondi struct ov5640_timings {
3773145efcdSJacopo Mondi 	/* Analog crop rectangle. */
3783145efcdSJacopo Mondi 	struct v4l2_rect analog_crop;
3793145efcdSJacopo Mondi 	/* Visibile crop: from analog crop top-left corner. */
3803145efcdSJacopo Mondi 	struct v4l2_rect crop;
3815113d5b3SJacopo Mondi 	/* Total pixels per line: width + fixed hblank. */
382476dec01SMaxime Ripard 	u32 htot;
3835113d5b3SJacopo Mondi 	/* Default vertical blanking: frame height = height + vblank. */
3843145efcdSJacopo Mondi 	u32 vblank_def;
3855113d5b3SJacopo Mondi };
3865113d5b3SJacopo Mondi 
3875113d5b3SJacopo Mondi struct ov5640_mode_info {
3885113d5b3SJacopo Mondi 	enum ov5640_mode_id id;
3895113d5b3SJacopo Mondi 	enum ov5640_downsize_mode dn_mode;
3905113d5b3SJacopo Mondi 	enum ov5640_pixel_rate_id pixel_rate;
3915113d5b3SJacopo Mondi 
3925113d5b3SJacopo Mondi 	unsigned int width;
3935113d5b3SJacopo Mondi 	unsigned int height;
3945113d5b3SJacopo Mondi 
3955113d5b3SJacopo Mondi 	struct ov5640_timings dvp_timings;
3965113d5b3SJacopo Mondi 	struct ov5640_timings csi2_timings;
3975113d5b3SJacopo Mondi 
39819a81c14SSteve Longerbeam 	const struct reg_value *reg_data;
39919a81c14SSteve Longerbeam 	u32 reg_data_size;
4005113d5b3SJacopo Mondi 
4015113d5b3SJacopo Mondi 	/* Used by s_frame_interval only. */
4025554c80eSAdam Ford 	u32 max_fps;
40319f2e3e6SHugues Fruchet 	u32 def_fps;
40419a81c14SSteve Longerbeam };
40519a81c14SSteve Longerbeam 
40619a81c14SSteve Longerbeam struct ov5640_ctrls {
40719a81c14SSteve Longerbeam 	struct v4l2_ctrl_handler handler;
408cc196e48SBenoit Parrot 	struct v4l2_ctrl *pixel_rate;
4097a3b8d4bSJacopo Mondi 	struct v4l2_ctrl *link_freq;
41032979f67SJacopo Mondi 	struct v4l2_ctrl *hblank;
411bce93b82SJacopo Mondi 	struct v4l2_ctrl *vblank;
41219a81c14SSteve Longerbeam 	struct {
41319a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_exp;
41419a81c14SSteve Longerbeam 		struct v4l2_ctrl *exposure;
41519a81c14SSteve Longerbeam 	};
41619a81c14SSteve Longerbeam 	struct {
41719a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_wb;
41819a81c14SSteve Longerbeam 		struct v4l2_ctrl *blue_balance;
41919a81c14SSteve Longerbeam 		struct v4l2_ctrl *red_balance;
42019a81c14SSteve Longerbeam 	};
42119a81c14SSteve Longerbeam 	struct {
42219a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_gain;
42319a81c14SSteve Longerbeam 		struct v4l2_ctrl *gain;
42419a81c14SSteve Longerbeam 	};
42519a81c14SSteve Longerbeam 	struct v4l2_ctrl *brightness;
4261068fecaSMylène Josserand 	struct v4l2_ctrl *light_freq;
42719a81c14SSteve Longerbeam 	struct v4l2_ctrl *saturation;
42819a81c14SSteve Longerbeam 	struct v4l2_ctrl *contrast;
42919a81c14SSteve Longerbeam 	struct v4l2_ctrl *hue;
43019a81c14SSteve Longerbeam 	struct v4l2_ctrl *test_pattern;
431ce85705aSHugues Fruchet 	struct v4l2_ctrl *hflip;
432ce85705aSHugues Fruchet 	struct v4l2_ctrl *vflip;
43319a81c14SSteve Longerbeam };
43419a81c14SSteve Longerbeam 
43519a81c14SSteve Longerbeam struct ov5640_dev {
43619a81c14SSteve Longerbeam 	struct i2c_client *i2c_client;
43719a81c14SSteve Longerbeam 	struct v4l2_subdev sd;
43819a81c14SSteve Longerbeam 	struct media_pad pad;
43919a81c14SSteve Longerbeam 	struct v4l2_fwnode_endpoint ep; /* the parsed DT endpoint info */
44019a81c14SSteve Longerbeam 	struct clk *xclk; /* system clock to OV5640 */
44119a81c14SSteve Longerbeam 	u32 xclk_freq;
44219a81c14SSteve Longerbeam 
44319a81c14SSteve Longerbeam 	struct regulator_bulk_data supplies[OV5640_NUM_SUPPLIES];
44419a81c14SSteve Longerbeam 	struct gpio_desc *reset_gpio;
44519a81c14SSteve Longerbeam 	struct gpio_desc *pwdn_gpio;
446c3f3ba3eSHugues Fruchet 	bool   upside_down;
44719a81c14SSteve Longerbeam 
44819a81c14SSteve Longerbeam 	/* lock to protect all members below */
44919a81c14SSteve Longerbeam 	struct mutex lock;
45019a81c14SSteve Longerbeam 
45119a81c14SSteve Longerbeam 	struct v4l2_mbus_framefmt fmt;
452fb98e29fSHugues Fruchet 	bool pending_fmt_change;
45319a81c14SSteve Longerbeam 
45419a81c14SSteve Longerbeam 	const struct ov5640_mode_info *current_mode;
455985cdcb0SHugues Fruchet 	const struct ov5640_mode_info *last_mode;
45619a81c14SSteve Longerbeam 	enum ov5640_frame_rate current_fr;
45719a81c14SSteve Longerbeam 	struct v4l2_fract frame_interval;
4583c28588fSJacopo Mondi 	s64 current_link_freq;
45919a81c14SSteve Longerbeam 
46019a81c14SSteve Longerbeam 	struct ov5640_ctrls ctrls;
46119a81c14SSteve Longerbeam 
46219a81c14SSteve Longerbeam 	u32 prev_sysclk, prev_hts;
46319a81c14SSteve Longerbeam 	u32 ae_low, ae_high, ae_target;
46419a81c14SSteve Longerbeam 
46519a81c14SSteve Longerbeam 	bool pending_mode_change;
46619a81c14SSteve Longerbeam 	bool streaming;
46719a81c14SSteve Longerbeam };
46819a81c14SSteve Longerbeam 
46919a81c14SSteve Longerbeam static inline struct ov5640_dev *to_ov5640_dev(struct v4l2_subdev *sd)
47019a81c14SSteve Longerbeam {
47119a81c14SSteve Longerbeam 	return container_of(sd, struct ov5640_dev, sd);
47219a81c14SSteve Longerbeam }
47319a81c14SSteve Longerbeam 
47419a81c14SSteve Longerbeam static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
47519a81c14SSteve Longerbeam {
47619a81c14SSteve Longerbeam 	return &container_of(ctrl->handler, struct ov5640_dev,
47719a81c14SSteve Longerbeam 			     ctrls.handler)->sd;
47819a81c14SSteve Longerbeam }
47919a81c14SSteve Longerbeam 
4808e823f5cSJacopo Mondi static inline bool ov5640_is_csi2(const struct ov5640_dev *sensor)
4818e823f5cSJacopo Mondi {
4828e823f5cSJacopo Mondi 	return sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY;
4838e823f5cSJacopo Mondi }
4848e823f5cSJacopo Mondi 
485a89f14bbSJacopo Mondi static inline const struct ov5640_pixfmt *
486a89f14bbSJacopo Mondi ov5640_formats(struct ov5640_dev *sensor)
487a89f14bbSJacopo Mondi {
488a89f14bbSJacopo Mondi 	return ov5640_is_csi2(sensor) ? ov5640_csi2_formats
489a89f14bbSJacopo Mondi 				      : ov5640_dvp_formats;
490a89f14bbSJacopo Mondi }
491a89f14bbSJacopo Mondi 
492a89f14bbSJacopo Mondi static const struct ov5640_pixfmt *
493a89f14bbSJacopo Mondi ov5640_code_to_pixfmt(struct ov5640_dev *sensor, u32 code)
494a89f14bbSJacopo Mondi {
495a89f14bbSJacopo Mondi 	const struct ov5640_pixfmt *formats = ov5640_formats(sensor);
496a89f14bbSJacopo Mondi 	unsigned int i;
497a89f14bbSJacopo Mondi 
498a89f14bbSJacopo Mondi 	for (i = 0; formats[i].code; ++i) {
499a89f14bbSJacopo Mondi 		if (formats[i].code == code)
500a89f14bbSJacopo Mondi 			return &formats[i];
501a89f14bbSJacopo Mondi 	}
502a89f14bbSJacopo Mondi 
503a89f14bbSJacopo Mondi 	return &formats[0];
504a89f14bbSJacopo Mondi }
505a89f14bbSJacopo Mondi 
506a89f14bbSJacopo Mondi static u32 ov5640_code_to_bpp(struct ov5640_dev *sensor, u32 code)
507a89f14bbSJacopo Mondi {
508a89f14bbSJacopo Mondi 	const struct ov5640_pixfmt *format = ov5640_code_to_pixfmt(sensor,
509a89f14bbSJacopo Mondi 								   code);
510a89f14bbSJacopo Mondi 
511a89f14bbSJacopo Mondi 	return format->bpp;
512a89f14bbSJacopo Mondi }
513a89f14bbSJacopo Mondi 
51419a81c14SSteve Longerbeam /*
51519a81c14SSteve Longerbeam  * FIXME: all of these register tables are likely filled with
51619a81c14SSteve Longerbeam  * entries that set the register to their power-on default values,
51719a81c14SSteve Longerbeam  * and which are otherwise not touched by this driver. Those entries
51819a81c14SSteve Longerbeam  * should be identified and removed to speed register load time
51919a81c14SSteve Longerbeam  * over i2c.
52019a81c14SSteve Longerbeam  */
521fb98e29fSHugues Fruchet /* YUV422 UYVY VGA@30fps */
52290b0f355SJacopo Mondi 
52390b0f355SJacopo Mondi static const struct v4l2_mbus_framefmt ov5640_default_fmt = {
52490b0f355SJacopo Mondi 	.code = MEDIA_BUS_FMT_UYVY8_2X8,
52590b0f355SJacopo Mondi 	.width = 640,
52690b0f355SJacopo Mondi 	.height = 480,
52790b0f355SJacopo Mondi 	.colorspace = V4L2_COLORSPACE_SRGB,
52890b0f355SJacopo Mondi 	.ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SRGB),
52990b0f355SJacopo Mondi 	.quantization = V4L2_QUANTIZATION_FULL_RANGE,
53090b0f355SJacopo Mondi 	.xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SRGB),
53190b0f355SJacopo Mondi 	.field = V4L2_FIELD_NONE,
53290b0f355SJacopo Mondi };
53390b0f355SJacopo Mondi 
534e4359019SJacopo Mondi static const struct reg_value ov5640_init_setting[] = {
53519a81c14SSteve Longerbeam 	{0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0},
536576f5d4bSLad Prabhakar 	{0x3103, 0x03, 0, 0}, {0x3630, 0x36, 0, 0},
53719a81c14SSteve Longerbeam 	{0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0},
53819a81c14SSteve Longerbeam 	{0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0},
53919a81c14SSteve Longerbeam 	{0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0},
54019a81c14SSteve Longerbeam 	{0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, {0x3906, 0x10, 0, 0},
54119a81c14SSteve Longerbeam 	{0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, {0x3600, 0x08, 0, 0},
54219a81c14SSteve Longerbeam 	{0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, {0x3620, 0x52, 0, 0},
54319a81c14SSteve Longerbeam 	{0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, {0x3a13, 0x43, 0, 0},
54419a81c14SSteve Longerbeam 	{0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3635, 0x13, 0, 0},
54519a81c14SSteve Longerbeam 	{0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, {0x3622, 0x01, 0, 0},
54619a81c14SSteve Longerbeam 	{0x3c01, 0xa4, 0, 0}, {0x3c04, 0x28, 0, 0}, {0x3c05, 0x98, 0, 0},
54719a81c14SSteve Longerbeam 	{0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0},
54819a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
54919a81c14SSteve Longerbeam 	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
5503145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
55119a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
55219a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
55319a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
55419a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
55519a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
55619a81c14SSteve Longerbeam 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0},
55719a81c14SSteve Longerbeam 	{0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0},
558aa4bb8b8SJacopo Mondi 	{0x302e, 0x08, 0, 0}, {0x4300, 0x3f, 0, 0},
5592b5c18f9SChen-Yu Tsai 	{0x501f, 0x00, 0, 0}, {0x4407, 0x04, 0, 0},
56019a81c14SSteve Longerbeam 	{0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
561aa4bb8b8SJacopo Mondi 	{0x4837, 0x0a, 0, 0}, {0x3824, 0x02, 0, 0},
56219a81c14SSteve Longerbeam 	{0x5000, 0xa7, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0},
56319a81c14SSteve Longerbeam 	{0x5181, 0xf2, 0, 0}, {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0},
56419a81c14SSteve Longerbeam 	{0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0},
56519a81c14SSteve Longerbeam 	{0x5187, 0x09, 0, 0}, {0x5188, 0x09, 0, 0}, {0x5189, 0x88, 0, 0},
56619a81c14SSteve Longerbeam 	{0x518a, 0x54, 0, 0}, {0x518b, 0xee, 0, 0}, {0x518c, 0xb2, 0, 0},
56719a81c14SSteve Longerbeam 	{0x518d, 0x50, 0, 0}, {0x518e, 0x34, 0, 0}, {0x518f, 0x6b, 0, 0},
56819a81c14SSteve Longerbeam 	{0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0},
56919a81c14SSteve Longerbeam 	{0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0},
57019a81c14SSteve Longerbeam 	{0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0},
57119a81c14SSteve Longerbeam 	{0x5199, 0x6c, 0, 0}, {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0},
57219a81c14SSteve Longerbeam 	{0x519c, 0x09, 0, 0}, {0x519d, 0x2b, 0, 0}, {0x519e, 0x38, 0, 0},
57319a81c14SSteve Longerbeam 	{0x5381, 0x1e, 0, 0}, {0x5382, 0x5b, 0, 0}, {0x5383, 0x08, 0, 0},
57419a81c14SSteve Longerbeam 	{0x5384, 0x0a, 0, 0}, {0x5385, 0x7e, 0, 0}, {0x5386, 0x88, 0, 0},
57519a81c14SSteve Longerbeam 	{0x5387, 0x7c, 0, 0}, {0x5388, 0x6c, 0, 0}, {0x5389, 0x10, 0, 0},
57619a81c14SSteve Longerbeam 	{0x538a, 0x01, 0, 0}, {0x538b, 0x98, 0, 0}, {0x5300, 0x08, 0, 0},
57719a81c14SSteve Longerbeam 	{0x5301, 0x30, 0, 0}, {0x5302, 0x10, 0, 0}, {0x5303, 0x00, 0, 0},
57819a81c14SSteve Longerbeam 	{0x5304, 0x08, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x08, 0, 0},
57919a81c14SSteve Longerbeam 	{0x5307, 0x16, 0, 0}, {0x5309, 0x08, 0, 0}, {0x530a, 0x30, 0, 0},
58019a81c14SSteve Longerbeam 	{0x530b, 0x04, 0, 0}, {0x530c, 0x06, 0, 0}, {0x5480, 0x01, 0, 0},
58119a81c14SSteve Longerbeam 	{0x5481, 0x08, 0, 0}, {0x5482, 0x14, 0, 0}, {0x5483, 0x28, 0, 0},
58219a81c14SSteve Longerbeam 	{0x5484, 0x51, 0, 0}, {0x5485, 0x65, 0, 0}, {0x5486, 0x71, 0, 0},
58319a81c14SSteve Longerbeam 	{0x5487, 0x7d, 0, 0}, {0x5488, 0x87, 0, 0}, {0x5489, 0x91, 0, 0},
58419a81c14SSteve Longerbeam 	{0x548a, 0x9a, 0, 0}, {0x548b, 0xaa, 0, 0}, {0x548c, 0xb8, 0, 0},
58519a81c14SSteve Longerbeam 	{0x548d, 0xcd, 0, 0}, {0x548e, 0xdd, 0, 0}, {0x548f, 0xea, 0, 0},
58619a81c14SSteve Longerbeam 	{0x5490, 0x1d, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5583, 0x40, 0, 0},
58719a81c14SSteve Longerbeam 	{0x5584, 0x10, 0, 0}, {0x5589, 0x10, 0, 0}, {0x558a, 0x00, 0, 0},
58819a81c14SSteve Longerbeam 	{0x558b, 0xf8, 0, 0}, {0x5800, 0x23, 0, 0}, {0x5801, 0x14, 0, 0},
58919a81c14SSteve Longerbeam 	{0x5802, 0x0f, 0, 0}, {0x5803, 0x0f, 0, 0}, {0x5804, 0x12, 0, 0},
59019a81c14SSteve Longerbeam 	{0x5805, 0x26, 0, 0}, {0x5806, 0x0c, 0, 0}, {0x5807, 0x08, 0, 0},
59119a81c14SSteve Longerbeam 	{0x5808, 0x05, 0, 0}, {0x5809, 0x05, 0, 0}, {0x580a, 0x08, 0, 0},
59219a81c14SSteve Longerbeam 	{0x580b, 0x0d, 0, 0}, {0x580c, 0x08, 0, 0}, {0x580d, 0x03, 0, 0},
59319a81c14SSteve Longerbeam 	{0x580e, 0x00, 0, 0}, {0x580f, 0x00, 0, 0}, {0x5810, 0x03, 0, 0},
59419a81c14SSteve Longerbeam 	{0x5811, 0x09, 0, 0}, {0x5812, 0x07, 0, 0}, {0x5813, 0x03, 0, 0},
59519a81c14SSteve Longerbeam 	{0x5814, 0x00, 0, 0}, {0x5815, 0x01, 0, 0}, {0x5816, 0x03, 0, 0},
59619a81c14SSteve Longerbeam 	{0x5817, 0x08, 0, 0}, {0x5818, 0x0d, 0, 0}, {0x5819, 0x08, 0, 0},
59719a81c14SSteve Longerbeam 	{0x581a, 0x05, 0, 0}, {0x581b, 0x06, 0, 0}, {0x581c, 0x08, 0, 0},
59819a81c14SSteve Longerbeam 	{0x581d, 0x0e, 0, 0}, {0x581e, 0x29, 0, 0}, {0x581f, 0x17, 0, 0},
59919a81c14SSteve Longerbeam 	{0x5820, 0x11, 0, 0}, {0x5821, 0x11, 0, 0}, {0x5822, 0x15, 0, 0},
60019a81c14SSteve Longerbeam 	{0x5823, 0x28, 0, 0}, {0x5824, 0x46, 0, 0}, {0x5825, 0x26, 0, 0},
60119a81c14SSteve Longerbeam 	{0x5826, 0x08, 0, 0}, {0x5827, 0x26, 0, 0}, {0x5828, 0x64, 0, 0},
60219a81c14SSteve Longerbeam 	{0x5829, 0x26, 0, 0}, {0x582a, 0x24, 0, 0}, {0x582b, 0x22, 0, 0},
60319a81c14SSteve Longerbeam 	{0x582c, 0x24, 0, 0}, {0x582d, 0x24, 0, 0}, {0x582e, 0x06, 0, 0},
60419a81c14SSteve Longerbeam 	{0x582f, 0x22, 0, 0}, {0x5830, 0x40, 0, 0}, {0x5831, 0x42, 0, 0},
60519a81c14SSteve Longerbeam 	{0x5832, 0x24, 0, 0}, {0x5833, 0x26, 0, 0}, {0x5834, 0x24, 0, 0},
60619a81c14SSteve Longerbeam 	{0x5835, 0x22, 0, 0}, {0x5836, 0x22, 0, 0}, {0x5837, 0x26, 0, 0},
60719a81c14SSteve Longerbeam 	{0x5838, 0x44, 0, 0}, {0x5839, 0x24, 0, 0}, {0x583a, 0x26, 0, 0},
60819a81c14SSteve Longerbeam 	{0x583b, 0x28, 0, 0}, {0x583c, 0x42, 0, 0}, {0x583d, 0xce, 0, 0},
60919a81c14SSteve Longerbeam 	{0x5025, 0x00, 0, 0}, {0x3a0f, 0x30, 0, 0}, {0x3a10, 0x28, 0, 0},
61019a81c14SSteve Longerbeam 	{0x3a1b, 0x30, 0, 0}, {0x3a1e, 0x26, 0, 0}, {0x3a11, 0x60, 0, 0},
61119a81c14SSteve Longerbeam 	{0x3a1f, 0x14, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3c00, 0x04, 0, 300},
61219a81c14SSteve Longerbeam };
61319a81c14SSteve Longerbeam 
614db15c195SJacopo Mondi static const struct reg_value ov5640_setting_low_res[] = {
615c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
61619a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
617ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
6183145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
61919a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
62019a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
62119a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
62219a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
62319a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
6242b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
625e15197bdSJacopo Mondi 	{0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0},
62619a81c14SSteve Longerbeam };
62719a81c14SSteve Longerbeam 
628086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_720P_1280_720[] = {
629c14d107eSMaxime Ripard 	{0x3c07, 0x07, 0, 0},
63019a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
631ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
6323145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
63319a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
63419a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0},
63519a81c14SSteve Longerbeam 	{0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0},
63619a81c14SSteve Longerbeam 	{0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0},
63719a81c14SSteve Longerbeam 	{0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0},
6382b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
63919a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
64019a81c14SSteve Longerbeam 	{0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0},
64119a81c14SSteve Longerbeam };
64219a81c14SSteve Longerbeam 
643086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_1080P_1920_1080[] = {
644c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
64519a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
646ce85705aSHugues Fruchet 	{0x3814, 0x11, 0, 0},
6473145efcdSJacopo Mondi 	{0x3815, 0x11, 0, 0},
64819a81c14SSteve Longerbeam 	{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
64919a81c14SSteve Longerbeam 	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
65019a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
65119a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
65219a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
6532b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0},
65419a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
655c14d107eSMaxime Ripard 	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0},
656c14d107eSMaxime Ripard 	{0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0},
65719a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
658476dec01SMaxime Ripard 	{0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0},
65919a81c14SSteve Longerbeam 	{0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0},
66019a81c14SSteve Longerbeam 	{0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0},
66119a81c14SSteve Longerbeam 	{0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0},
6622b5c18f9SChen-Yu Tsai 	{0x3a15, 0x60, 0, 0}, {0x4407, 0x04, 0, 0},
66319a81c14SSteve Longerbeam 	{0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0},
66492b9096cSBenoit Parrot 	{0x4005, 0x1a, 0, 0},
66519a81c14SSteve Longerbeam };
66619a81c14SSteve Longerbeam 
667086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_QSXGA_2592_1944[] = {
668c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
66919a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
670ce85705aSHugues Fruchet 	{0x3814, 0x11, 0, 0},
6713145efcdSJacopo Mondi 	{0x3815, 0x11, 0, 0},
67219a81c14SSteve Longerbeam 	{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
67319a81c14SSteve Longerbeam 	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
67419a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
67519a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
67619a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
6772b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0},
67819a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
67919a81c14SSteve Longerbeam 	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70},
68019a81c14SSteve Longerbeam };
68119a81c14SSteve Longerbeam 
6825113d5b3SJacopo Mondi static const struct ov5640_mode_info ov5640_mode_data[OV5640_NUM_MODES] = {
6838409d017SJacopo Mondi 	{
6848409d017SJacopo Mondi 		/* 160x120 */
6853145efcdSJacopo Mondi 		.id		= OV5640_MODE_QQVGA_160_120,
6863145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
6873145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
6885113d5b3SJacopo Mondi 		.width		= 160,
6895113d5b3SJacopo Mondi 		.height		= 120,
6905113d5b3SJacopo Mondi 		.dvp_timings = {
6913145efcdSJacopo Mondi 			.analog_crop = {
6923145efcdSJacopo Mondi 				.left	= 0,
6933145efcdSJacopo Mondi 				.top	= 4,
6943145efcdSJacopo Mondi 				.width	= 2624,
6953145efcdSJacopo Mondi 				.height	= 1944,
6963145efcdSJacopo Mondi 			},
6973145efcdSJacopo Mondi 			.crop = {
6983145efcdSJacopo Mondi 				.left	= 16,
6993145efcdSJacopo Mondi 				.top	= 6,
7003145efcdSJacopo Mondi 				.width	= 160,
7013145efcdSJacopo Mondi 				.height	= 120,
7023145efcdSJacopo Mondi 			},
7033145efcdSJacopo Mondi 			.htot		= 1896,
7043145efcdSJacopo Mondi 			.vblank_def	= 864,
7055113d5b3SJacopo Mondi 		},
7065113d5b3SJacopo Mondi 		.csi2_timings = {
7075113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
7085113d5b3SJacopo Mondi 			.analog_crop = {
7095113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
7105113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
7115113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
7125113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
7135113d5b3SJacopo Mondi 			},
7145113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
7155113d5b3SJacopo Mondi 			.crop = {
7165113d5b3SJacopo Mondi 				.left	= 2,
7175113d5b3SJacopo Mondi 				.top	= 4,
7185113d5b3SJacopo Mondi 				.width	= 160,
7195113d5b3SJacopo Mondi 				.height	= 120,
7205113d5b3SJacopo Mondi 			},
721961bed9fSJacopo Mondi 			.htot		= 1600,
722961bed9fSJacopo Mondi 			.vblank_def	= 878,
7235113d5b3SJacopo Mondi 		},
724db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
725db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
72619f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
72719f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
7288409d017SJacopo Mondi 	}, {
7298409d017SJacopo Mondi 		/* 176x144 */
7303145efcdSJacopo Mondi 		.id		= OV5640_MODE_QCIF_176_144,
7313145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
7323145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
7335113d5b3SJacopo Mondi 		.width		= 176,
7345113d5b3SJacopo Mondi 		.height		= 144,
7355113d5b3SJacopo Mondi 		.dvp_timings = {
7363145efcdSJacopo Mondi 			.analog_crop = {
7373145efcdSJacopo Mondi 				.left	= 0,
7383145efcdSJacopo Mondi 				.top	= 4,
7393145efcdSJacopo Mondi 				.width	= 2624,
7403145efcdSJacopo Mondi 				.height	= 1944,
7413145efcdSJacopo Mondi 			},
7423145efcdSJacopo Mondi 			.crop = {
7433145efcdSJacopo Mondi 				.left	= 16,
7443145efcdSJacopo Mondi 				.top	= 6,
7453145efcdSJacopo Mondi 				.width	= 176,
7463145efcdSJacopo Mondi 				.height	= 144,
7473145efcdSJacopo Mondi 			},
7483145efcdSJacopo Mondi 			.htot		= 1896,
7493145efcdSJacopo Mondi 			.vblank_def	= 840,
7505113d5b3SJacopo Mondi 		},
7515113d5b3SJacopo Mondi 		.csi2_timings = {
7525113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
7535113d5b3SJacopo Mondi 			.analog_crop = {
7545113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
7555113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
7565113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
7575113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
7585113d5b3SJacopo Mondi 			},
7595113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
7605113d5b3SJacopo Mondi 			.crop = {
7615113d5b3SJacopo Mondi 				.left	= 2,
7625113d5b3SJacopo Mondi 				.top	= 4,
7635113d5b3SJacopo Mondi 				.width	= 176,
7645113d5b3SJacopo Mondi 				.height	= 144,
7655113d5b3SJacopo Mondi 			},
766961bed9fSJacopo Mondi 			.htot		= 1600,
767961bed9fSJacopo Mondi 			.vblank_def	= 854,
7685113d5b3SJacopo Mondi 		},
769db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
770db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
77119f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
77219f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
7738409d017SJacopo Mondi 	}, {
7748409d017SJacopo Mondi 		/* 320x240 */
7753145efcdSJacopo Mondi 		.id		= OV5640_MODE_QVGA_320_240,
7763145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
7775113d5b3SJacopo Mondi 		.width		= 320,
7785113d5b3SJacopo Mondi 		.height		= 240,
7793145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
7805113d5b3SJacopo Mondi 		.dvp_timings = {
7813145efcdSJacopo Mondi 			.analog_crop = {
7823145efcdSJacopo Mondi 				.left	= 0,
7833145efcdSJacopo Mondi 				.top	= 4,
7843145efcdSJacopo Mondi 				.width	= 2624,
7853145efcdSJacopo Mondi 				.height	= 1944,
7863145efcdSJacopo Mondi 			},
7873145efcdSJacopo Mondi 			.crop = {
7883145efcdSJacopo Mondi 				.left	= 16,
7893145efcdSJacopo Mondi 				.top	= 6,
7903145efcdSJacopo Mondi 				.width	= 320,
7913145efcdSJacopo Mondi 				.height	= 240,
7923145efcdSJacopo Mondi 			},
7933145efcdSJacopo Mondi 			.htot		= 1896,
7943145efcdSJacopo Mondi 			.vblank_def	= 744,
7955113d5b3SJacopo Mondi 		},
7965113d5b3SJacopo Mondi 		.csi2_timings = {
7975113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
7985113d5b3SJacopo Mondi 			.analog_crop = {
7995113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
8005113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
8015113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
8025113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
8035113d5b3SJacopo Mondi 			},
8045113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
8055113d5b3SJacopo Mondi 			.crop = {
8065113d5b3SJacopo Mondi 				.left	= 2,
8075113d5b3SJacopo Mondi 				.top	= 4,
8085113d5b3SJacopo Mondi 				.width	= 320,
8095113d5b3SJacopo Mondi 				.height	= 240,
8105113d5b3SJacopo Mondi 			},
811961bed9fSJacopo Mondi 			.htot		= 1600,
812961bed9fSJacopo Mondi 			.vblank_def	= 760,
8135113d5b3SJacopo Mondi 		},
814db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
815db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
81619f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
81719f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
8188409d017SJacopo Mondi 	}, {
8198409d017SJacopo Mondi 		/* 640x480 */
8203145efcdSJacopo Mondi 		.id		= OV5640_MODE_VGA_640_480,
8213145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
8223145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
8235113d5b3SJacopo Mondi 		.width		= 640,
8245113d5b3SJacopo Mondi 		.height		= 480,
8255113d5b3SJacopo Mondi 		.dvp_timings = {
8263145efcdSJacopo Mondi 			.analog_crop = {
8273145efcdSJacopo Mondi 				.left	= 0,
8283145efcdSJacopo Mondi 				.top	= 4,
8293145efcdSJacopo Mondi 				.width	= 2624,
8303145efcdSJacopo Mondi 				.height	= 1944,
8313145efcdSJacopo Mondi 			},
8323145efcdSJacopo Mondi 			.crop = {
8333145efcdSJacopo Mondi 				.left	= 16,
8343145efcdSJacopo Mondi 				.top	= 6,
8353145efcdSJacopo Mondi 				.width	= 640,
8363145efcdSJacopo Mondi 				.height	= 480,
8373145efcdSJacopo Mondi 			},
8383145efcdSJacopo Mondi 			.htot		= 1896,
8393145efcdSJacopo Mondi 			.vblank_def	= 600,
8405113d5b3SJacopo Mondi 		},
8415113d5b3SJacopo Mondi 		.csi2_timings = {
8425113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
8435113d5b3SJacopo Mondi 			.analog_crop = {
8445113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
8455113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
8465113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
8475113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
8485113d5b3SJacopo Mondi 			},
8495113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
8505113d5b3SJacopo Mondi 			.crop = {
8515113d5b3SJacopo Mondi 				.left	= 2,
8525113d5b3SJacopo Mondi 				.top	= 4,
8535113d5b3SJacopo Mondi 				.width	= 640,
8545113d5b3SJacopo Mondi 				.height	= 480,
8555113d5b3SJacopo Mondi 			},
856961bed9fSJacopo Mondi 			.htot		= 1600,
857961bed9fSJacopo Mondi 			.vblank_def	= 520,
8585113d5b3SJacopo Mondi 		},
859db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
860db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
86119f2e3e6SHugues Fruchet 		.max_fps	= OV5640_60_FPS,
86219f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
8638409d017SJacopo Mondi 	}, {
8648409d017SJacopo Mondi 		/* 720x480 */
8653145efcdSJacopo Mondi 		.id		= OV5640_MODE_NTSC_720_480,
8663145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
8675113d5b3SJacopo Mondi 		.width		= 720,
8685113d5b3SJacopo Mondi 		.height		= 480,
8693145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
8705113d5b3SJacopo Mondi 		.dvp_timings = {
8713145efcdSJacopo Mondi 			.analog_crop = {
8723145efcdSJacopo Mondi 				.left	= 0,
8733145efcdSJacopo Mondi 				.top	= 4,
8743145efcdSJacopo Mondi 				.width	= 2624,
8753145efcdSJacopo Mondi 				.height	= 1944,
8763145efcdSJacopo Mondi 			},
8773145efcdSJacopo Mondi 			.crop = {
878e74ef55bSJacopo Mondi 				.left	= 56,
8793145efcdSJacopo Mondi 				.top	= 60,
8803145efcdSJacopo Mondi 				.width	= 720,
8813145efcdSJacopo Mondi 				.height	= 480,
8823145efcdSJacopo Mondi 			},
8833145efcdSJacopo Mondi 			.htot		= 1896,
8843145efcdSJacopo Mondi 			.vblank_def	= 504,
8855113d5b3SJacopo Mondi 		},
8865113d5b3SJacopo Mondi 		.csi2_timings = {
8875113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
8885113d5b3SJacopo Mondi 			.analog_crop = {
8895113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
8905113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
8915113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
8925113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
8935113d5b3SJacopo Mondi 			},
8945113d5b3SJacopo Mondi 			.crop = {
8955113d5b3SJacopo Mondi 				.left	= 56,
8965113d5b3SJacopo Mondi 				.top	= 60,
8975113d5b3SJacopo Mondi 				.width	= 720,
8985113d5b3SJacopo Mondi 				.height	= 480,
8995113d5b3SJacopo Mondi 			},
9005113d5b3SJacopo Mondi 			.htot		= 1896,
901961bed9fSJacopo Mondi 			.vblank_def	= 1206,
9025113d5b3SJacopo Mondi 		},
903db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
904db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
90519f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
90619f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
9078409d017SJacopo Mondi 	}, {
9088409d017SJacopo Mondi 		/* 720x576 */
9093145efcdSJacopo Mondi 		.id		= OV5640_MODE_PAL_720_576,
9103145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
9115113d5b3SJacopo Mondi 		.width		= 720,
9125113d5b3SJacopo Mondi 		.height		= 576,
9133145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
9145113d5b3SJacopo Mondi 		.dvp_timings = {
9153145efcdSJacopo Mondi 			.analog_crop = {
9163145efcdSJacopo Mondi 				.left	= 0,
9173145efcdSJacopo Mondi 				.top	= 4,
9183145efcdSJacopo Mondi 				.width	= 2624,
9193145efcdSJacopo Mondi 				.height	= 1944,
9203145efcdSJacopo Mondi 			},
9213145efcdSJacopo Mondi 			.crop = {
9223145efcdSJacopo Mondi 				.left	= 56,
9233145efcdSJacopo Mondi 				.top	= 6,
9243145efcdSJacopo Mondi 				.width	= 720,
9253145efcdSJacopo Mondi 				.height	= 576,
9263145efcdSJacopo Mondi 			},
9273145efcdSJacopo Mondi 			.htot		= 1896,
9283145efcdSJacopo Mondi 			.vblank_def	= 408,
9295113d5b3SJacopo Mondi 		},
9305113d5b3SJacopo Mondi 		.csi2_timings = {
9315113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
9325113d5b3SJacopo Mondi 			.analog_crop = {
9335113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
9345113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
9355113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
9365113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
9375113d5b3SJacopo Mondi 			},
9385113d5b3SJacopo Mondi 			.crop = {
9395113d5b3SJacopo Mondi 				.left	= 56,
9405113d5b3SJacopo Mondi 				.top	= 6,
9415113d5b3SJacopo Mondi 				.width	= 720,
9425113d5b3SJacopo Mondi 				.height	= 576,
9435113d5b3SJacopo Mondi 			},
9445113d5b3SJacopo Mondi 			.htot		= 1896,
945961bed9fSJacopo Mondi 			.vblank_def	= 1110,
9465113d5b3SJacopo Mondi 		},
947db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
948db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
94919f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
95019f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
9518409d017SJacopo Mondi 	}, {
9528409d017SJacopo Mondi 		/* 1024x768 */
9533145efcdSJacopo Mondi 		.id		= OV5640_MODE_XGA_1024_768,
9543145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
9553145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
9565113d5b3SJacopo Mondi 		.width		= 1024,
9575113d5b3SJacopo Mondi 		.height		= 768,
9585113d5b3SJacopo Mondi 		.dvp_timings = {
9593145efcdSJacopo Mondi 			.analog_crop = {
9603145efcdSJacopo Mondi 				.left	= 0,
9613145efcdSJacopo Mondi 				.top	= 4,
9623145efcdSJacopo Mondi 				.width	= 2624,
9633145efcdSJacopo Mondi 				.height	= 1944,
9643145efcdSJacopo Mondi 			},
9653145efcdSJacopo Mondi 			.crop = {
9663145efcdSJacopo Mondi 				.left	= 16,
9673145efcdSJacopo Mondi 				.top	= 6,
9683145efcdSJacopo Mondi 				.width	= 1024,
9693145efcdSJacopo Mondi 				.height	= 768,
9703145efcdSJacopo Mondi 			},
9713145efcdSJacopo Mondi 			.htot		= 1896,
9723145efcdSJacopo Mondi 			.vblank_def	= 312,
9735113d5b3SJacopo Mondi 		},
9745113d5b3SJacopo Mondi 		.csi2_timings = {
9755113d5b3SJacopo Mondi 			.analog_crop = {
9765113d5b3SJacopo Mondi 				.left	= 0,
9775113d5b3SJacopo Mondi 				.top	= 4,
9785113d5b3SJacopo Mondi 				.width	= OV5640_NATIVE_WIDTH,
9795113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
9805113d5b3SJacopo Mondi 			},
9815113d5b3SJacopo Mondi 			.crop = {
9825113d5b3SJacopo Mondi 				.left	= 16,
9835113d5b3SJacopo Mondi 				.top	= 6,
9845113d5b3SJacopo Mondi 				.width	= 1024,
9855113d5b3SJacopo Mondi 				.height	= 768,
9865113d5b3SJacopo Mondi 			},
9875113d5b3SJacopo Mondi 			.htot		= 1896,
988961bed9fSJacopo Mondi 			.vblank_def	= 918,
9895113d5b3SJacopo Mondi 		},
990db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
991db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
99219f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
99319f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
9948409d017SJacopo Mondi 	}, {
9958409d017SJacopo Mondi 		/* 1280x720 */
9963145efcdSJacopo Mondi 		.id		= OV5640_MODE_720P_1280_720,
9973145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
9983145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_124M,
9995113d5b3SJacopo Mondi 		.width		= 1280,
10005113d5b3SJacopo Mondi 		.height		= 720,
10015113d5b3SJacopo Mondi 		.dvp_timings = {
10023145efcdSJacopo Mondi 			.analog_crop = {
10033145efcdSJacopo Mondi 				.left	= 0,
10043145efcdSJacopo Mondi 				.top	= 250,
10053145efcdSJacopo Mondi 				.width	= 2624,
10063145efcdSJacopo Mondi 				.height	= 1456,
10073145efcdSJacopo Mondi 			},
10083145efcdSJacopo Mondi 			.crop = {
10093145efcdSJacopo Mondi 				.left	= 16,
10103145efcdSJacopo Mondi 				.top	= 4,
10113145efcdSJacopo Mondi 				.width	= 1280,
10123145efcdSJacopo Mondi 				.height	= 720,
10133145efcdSJacopo Mondi 			},
10143145efcdSJacopo Mondi 			.htot		= 1892,
10153145efcdSJacopo Mondi 			.vblank_def	= 20,
10165113d5b3SJacopo Mondi 		},
10175113d5b3SJacopo Mondi 		.csi2_timings = {
10185113d5b3SJacopo Mondi 			.analog_crop = {
10195113d5b3SJacopo Mondi 				.left	= 0,
10205113d5b3SJacopo Mondi 				.top	= 250,
10215113d5b3SJacopo Mondi 				.width	= 2624,
10225113d5b3SJacopo Mondi 				.height	= 1456,
10235113d5b3SJacopo Mondi 			},
10245113d5b3SJacopo Mondi 			.crop = {
10255113d5b3SJacopo Mondi 				.left	= 16,
10265113d5b3SJacopo Mondi 				.top	= 4,
10275113d5b3SJacopo Mondi 				.width	= 1280,
10285113d5b3SJacopo Mondi 				.height	= 720,
10295113d5b3SJacopo Mondi 			},
1030961bed9fSJacopo Mondi 			.htot		= 1600,
1031961bed9fSJacopo Mondi 			.vblank_def	= 560,
10325113d5b3SJacopo Mondi 		},
10333145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_720P_1280_720,
10343145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_720P_1280_720),
103519f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
103619f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
10378409d017SJacopo Mondi 	}, {
10388409d017SJacopo Mondi 		/* 1920x1080 */
10393145efcdSJacopo Mondi 		.id		= OV5640_MODE_1080P_1920_1080,
10403145efcdSJacopo Mondi 		.dn_mode	= SCALING,
10413145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_148M,
10425113d5b3SJacopo Mondi 		.width		= 1920,
10435113d5b3SJacopo Mondi 		.height		= 1080,
10445113d5b3SJacopo Mondi 		.dvp_timings = {
10453145efcdSJacopo Mondi 			.analog_crop = {
10463145efcdSJacopo Mondi 				.left	= 336,
10473145efcdSJacopo Mondi 				.top	= 434,
10483145efcdSJacopo Mondi 				.width	= 1952,
10493145efcdSJacopo Mondi 				.height	= 1088,
10503145efcdSJacopo Mondi 			},
10513145efcdSJacopo Mondi 			.crop = {
10523145efcdSJacopo Mondi 				.left	= 16,
10533145efcdSJacopo Mondi 				.top	= 4,
10543145efcdSJacopo Mondi 				.width	= 1920,
10553145efcdSJacopo Mondi 				.height	= 1080,
10563145efcdSJacopo Mondi 			},
10573145efcdSJacopo Mondi 			.htot		= 2500,
10583145efcdSJacopo Mondi 			.vblank_def	= 40,
10595113d5b3SJacopo Mondi 		},
10605113d5b3SJacopo Mondi 		.csi2_timings = {
10615113d5b3SJacopo Mondi 			/* Crop the full valid pixel array in the center. */
10625113d5b3SJacopo Mondi 			.analog_crop = {
10635113d5b3SJacopo Mondi 				.left	= 336,
10645113d5b3SJacopo Mondi 				.top	= 434,
10655113d5b3SJacopo Mondi 				.width	= 1952,
10665113d5b3SJacopo Mondi 				.height	= 1088,
10675113d5b3SJacopo Mondi 			},
10685113d5b3SJacopo Mondi 			/* Maintain a larger processing margins. */
10695113d5b3SJacopo Mondi 			.crop = {
10705113d5b3SJacopo Mondi 				.left	= 16,
10715113d5b3SJacopo Mondi 				.top	= 4,
10725113d5b3SJacopo Mondi 				.width	= 1920,
10735113d5b3SJacopo Mondi 				.height	= 1080,
10745113d5b3SJacopo Mondi 			},
1075961bed9fSJacopo Mondi 			.htot		= 2234,
1076961bed9fSJacopo Mondi 			.vblank_def	= 24,
10775113d5b3SJacopo Mondi 		},
10783145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_1080P_1920_1080,
10793145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_1080P_1920_1080),
108019f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
108119f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
10828409d017SJacopo Mondi 	}, {
10838409d017SJacopo Mondi 		/* 2592x1944 */
10843145efcdSJacopo Mondi 		.id		= OV5640_MODE_QSXGA_2592_1944,
10853145efcdSJacopo Mondi 		.dn_mode	= SCALING,
10863145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_168M,
10875113d5b3SJacopo Mondi 		.width		= OV5640_PIXEL_ARRAY_WIDTH,
10885113d5b3SJacopo Mondi 		.height		= OV5640_PIXEL_ARRAY_HEIGHT,
10895113d5b3SJacopo Mondi 		.dvp_timings = {
10903145efcdSJacopo Mondi 			.analog_crop = {
10913145efcdSJacopo Mondi 				.left	= 0,
10923145efcdSJacopo Mondi 				.top	= 0,
10933145efcdSJacopo Mondi 				.width	= 2624,
10943145efcdSJacopo Mondi 				.height	= 1952,
10953145efcdSJacopo Mondi 			},
10963145efcdSJacopo Mondi 			.crop = {
10973145efcdSJacopo Mondi 				.left	= 16,
10983145efcdSJacopo Mondi 				.top	= 4,
10993145efcdSJacopo Mondi 				.width	= 2592,
11003145efcdSJacopo Mondi 				.height	= 1944,
11013145efcdSJacopo Mondi 			},
11023145efcdSJacopo Mondi 			.htot		= 2844,
11033145efcdSJacopo Mondi 			.vblank_def	= 24,
11045113d5b3SJacopo Mondi 		},
11055113d5b3SJacopo Mondi 		.csi2_timings = {
11065113d5b3SJacopo Mondi 			/* Give more processing margin to full resolution. */
11075113d5b3SJacopo Mondi 			.analog_crop = {
11085113d5b3SJacopo Mondi 				.left	= 0,
11095113d5b3SJacopo Mondi 				.top	= 0,
11105113d5b3SJacopo Mondi 				.width	= OV5640_NATIVE_WIDTH,
11115113d5b3SJacopo Mondi 				.height	= 1952,
11125113d5b3SJacopo Mondi 			},
11135113d5b3SJacopo Mondi 			.crop = {
11145113d5b3SJacopo Mondi 				.left	= 16,
11155113d5b3SJacopo Mondi 				.top	= 4,
11165113d5b3SJacopo Mondi 				.width	= 2592,
11175113d5b3SJacopo Mondi 				.height	= 1944,
11185113d5b3SJacopo Mondi 			},
11195113d5b3SJacopo Mondi 			.htot		= 2844,
11205113d5b3SJacopo Mondi 			.vblank_def	= 24,
11215113d5b3SJacopo Mondi 		},
11223145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_QSXGA_2592_1944,
11233145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_QSXGA_2592_1944),
112419f2e3e6SHugues Fruchet 		.max_fps	= OV5640_15_FPS,
112519f2e3e6SHugues Fruchet 		.def_fps	= OV5640_15_FPS
11268409d017SJacopo Mondi 	},
112719a81c14SSteve Longerbeam };
112819a81c14SSteve Longerbeam 
11292de6bb97SJacopo Mondi static const struct ov5640_timings *
11302de6bb97SJacopo Mondi ov5640_timings(const struct ov5640_dev *sensor,
11312de6bb97SJacopo Mondi 	       const struct ov5640_mode_info *mode)
11322de6bb97SJacopo Mondi {
11332de6bb97SJacopo Mondi 	if (ov5640_is_csi2(sensor))
11342de6bb97SJacopo Mondi 		return &mode->csi2_timings;
11352de6bb97SJacopo Mondi 
11362de6bb97SJacopo Mondi 	return &mode->dvp_timings;
11372de6bb97SJacopo Mondi }
11382de6bb97SJacopo Mondi 
113919a81c14SSteve Longerbeam static int ov5640_init_slave_id(struct ov5640_dev *sensor)
114019a81c14SSteve Longerbeam {
114119a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
114219a81c14SSteve Longerbeam 	struct i2c_msg msg;
114319a81c14SSteve Longerbeam 	u8 buf[3];
114419a81c14SSteve Longerbeam 	int ret;
114519a81c14SSteve Longerbeam 
114619a81c14SSteve Longerbeam 	if (client->addr == OV5640_DEFAULT_SLAVE_ID)
114719a81c14SSteve Longerbeam 		return 0;
114819a81c14SSteve Longerbeam 
114919a81c14SSteve Longerbeam 	buf[0] = OV5640_REG_SLAVE_ID >> 8;
115019a81c14SSteve Longerbeam 	buf[1] = OV5640_REG_SLAVE_ID & 0xff;
115119a81c14SSteve Longerbeam 	buf[2] = client->addr << 1;
115219a81c14SSteve Longerbeam 
115319a81c14SSteve Longerbeam 	msg.addr = OV5640_DEFAULT_SLAVE_ID;
115419a81c14SSteve Longerbeam 	msg.flags = 0;
115519a81c14SSteve Longerbeam 	msg.buf = buf;
115619a81c14SSteve Longerbeam 	msg.len = sizeof(buf);
115719a81c14SSteve Longerbeam 
115819a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, &msg, 1);
115919a81c14SSteve Longerbeam 	if (ret < 0) {
116019a81c14SSteve Longerbeam 		dev_err(&client->dev, "%s: failed with %d\n", __func__, ret);
116119a81c14SSteve Longerbeam 		return ret;
116219a81c14SSteve Longerbeam 	}
116319a81c14SSteve Longerbeam 
116419a81c14SSteve Longerbeam 	return 0;
116519a81c14SSteve Longerbeam }
116619a81c14SSteve Longerbeam 
116719a81c14SSteve Longerbeam static int ov5640_write_reg(struct ov5640_dev *sensor, u16 reg, u8 val)
116819a81c14SSteve Longerbeam {
116919a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
117019a81c14SSteve Longerbeam 	struct i2c_msg msg;
117119a81c14SSteve Longerbeam 	u8 buf[3];
117219a81c14SSteve Longerbeam 	int ret;
117319a81c14SSteve Longerbeam 
117419a81c14SSteve Longerbeam 	buf[0] = reg >> 8;
117519a81c14SSteve Longerbeam 	buf[1] = reg & 0xff;
117619a81c14SSteve Longerbeam 	buf[2] = val;
117719a81c14SSteve Longerbeam 
117819a81c14SSteve Longerbeam 	msg.addr = client->addr;
117919a81c14SSteve Longerbeam 	msg.flags = client->flags;
118019a81c14SSteve Longerbeam 	msg.buf = buf;
118119a81c14SSteve Longerbeam 	msg.len = sizeof(buf);
118219a81c14SSteve Longerbeam 
118319a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, &msg, 1);
118419a81c14SSteve Longerbeam 	if (ret < 0) {
11853924c623SHugues Fruchet 		dev_err(&client->dev, "%s: error: reg=%x, val=%x\n",
118619a81c14SSteve Longerbeam 			__func__, reg, val);
118719a81c14SSteve Longerbeam 		return ret;
118819a81c14SSteve Longerbeam 	}
118919a81c14SSteve Longerbeam 
119019a81c14SSteve Longerbeam 	return 0;
119119a81c14SSteve Longerbeam }
119219a81c14SSteve Longerbeam 
119319a81c14SSteve Longerbeam static int ov5640_read_reg(struct ov5640_dev *sensor, u16 reg, u8 *val)
119419a81c14SSteve Longerbeam {
119519a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
119619a81c14SSteve Longerbeam 	struct i2c_msg msg[2];
119719a81c14SSteve Longerbeam 	u8 buf[2];
119819a81c14SSteve Longerbeam 	int ret;
119919a81c14SSteve Longerbeam 
120019a81c14SSteve Longerbeam 	buf[0] = reg >> 8;
120119a81c14SSteve Longerbeam 	buf[1] = reg & 0xff;
120219a81c14SSteve Longerbeam 
120319a81c14SSteve Longerbeam 	msg[0].addr = client->addr;
120419a81c14SSteve Longerbeam 	msg[0].flags = client->flags;
120519a81c14SSteve Longerbeam 	msg[0].buf = buf;
120619a81c14SSteve Longerbeam 	msg[0].len = sizeof(buf);
120719a81c14SSteve Longerbeam 
120819a81c14SSteve Longerbeam 	msg[1].addr = client->addr;
120919a81c14SSteve Longerbeam 	msg[1].flags = client->flags | I2C_M_RD;
121019a81c14SSteve Longerbeam 	msg[1].buf = buf;
121119a81c14SSteve Longerbeam 	msg[1].len = 1;
121219a81c14SSteve Longerbeam 
121319a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, msg, 2);
12143924c623SHugues Fruchet 	if (ret < 0) {
12153924c623SHugues Fruchet 		dev_err(&client->dev, "%s: error: reg=%x\n",
12163924c623SHugues Fruchet 			__func__, reg);
121719a81c14SSteve Longerbeam 		return ret;
12183924c623SHugues Fruchet 	}
121919a81c14SSteve Longerbeam 
122019a81c14SSteve Longerbeam 	*val = buf[0];
122119a81c14SSteve Longerbeam 	return 0;
122219a81c14SSteve Longerbeam }
122319a81c14SSteve Longerbeam 
122419a81c14SSteve Longerbeam static int ov5640_read_reg16(struct ov5640_dev *sensor, u16 reg, u16 *val)
122519a81c14SSteve Longerbeam {
122619a81c14SSteve Longerbeam 	u8 hi, lo;
122719a81c14SSteve Longerbeam 	int ret;
122819a81c14SSteve Longerbeam 
122919a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg, &hi);
123019a81c14SSteve Longerbeam 	if (ret)
123119a81c14SSteve Longerbeam 		return ret;
123219a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg + 1, &lo);
123319a81c14SSteve Longerbeam 	if (ret)
123419a81c14SSteve Longerbeam 		return ret;
123519a81c14SSteve Longerbeam 
123619a81c14SSteve Longerbeam 	*val = ((u16)hi << 8) | (u16)lo;
123719a81c14SSteve Longerbeam 	return 0;
123819a81c14SSteve Longerbeam }
123919a81c14SSteve Longerbeam 
124019a81c14SSteve Longerbeam static int ov5640_write_reg16(struct ov5640_dev *sensor, u16 reg, u16 val)
124119a81c14SSteve Longerbeam {
124219a81c14SSteve Longerbeam 	int ret;
124319a81c14SSteve Longerbeam 
124419a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, reg, val >> 8);
124519a81c14SSteve Longerbeam 	if (ret)
124619a81c14SSteve Longerbeam 		return ret;
124719a81c14SSteve Longerbeam 
124819a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, reg + 1, val & 0xff);
124919a81c14SSteve Longerbeam }
125019a81c14SSteve Longerbeam 
125119a81c14SSteve Longerbeam static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg,
125219a81c14SSteve Longerbeam 			  u8 mask, u8 val)
125319a81c14SSteve Longerbeam {
125419a81c14SSteve Longerbeam 	u8 readval;
125519a81c14SSteve Longerbeam 	int ret;
125619a81c14SSteve Longerbeam 
125719a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg, &readval);
125819a81c14SSteve Longerbeam 	if (ret)
125919a81c14SSteve Longerbeam 		return ret;
126019a81c14SSteve Longerbeam 
126119a81c14SSteve Longerbeam 	readval &= ~mask;
126219a81c14SSteve Longerbeam 	val &= mask;
126319a81c14SSteve Longerbeam 	val |= readval;
126419a81c14SSteve Longerbeam 
126519a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, reg, val);
126619a81c14SSteve Longerbeam }
126719a81c14SSteve Longerbeam 
1268aa288248SMaxime Ripard /*
1269aa288248SMaxime Ripard  * After trying the various combinations, reading various
1270f8a7647dSMauro Carvalho Chehab  * documentations spread around the net, and from the various
1271aa288248SMaxime Ripard  * feedback, the clock tree is probably as follows:
1272aa288248SMaxime Ripard  *
1273aa288248SMaxime Ripard  *   +--------------+
1274aa288248SMaxime Ripard  *   |  Ext. Clock  |
1275aa288248SMaxime Ripard  *   +-+------------+
1276aa288248SMaxime Ripard  *     |  +----------+
1277aa288248SMaxime Ripard  *     +->|   PLL1   | - reg 0x3036, for the multiplier
1278aa288248SMaxime Ripard  *        +-+--------+ - reg 0x3037, bits 0-3 for the pre-divider
1279aa288248SMaxime Ripard  *          |  +--------------+
1280aa288248SMaxime Ripard  *          +->| System Clock |  - reg 0x3035, bits 4-7
1281aa288248SMaxime Ripard  *             +-+------------+
1282aa288248SMaxime Ripard  *               |  +--------------+
1283aa288248SMaxime Ripard  *               +->| MIPI Divider | - reg 0x3035, bits 0-3
1284aa288248SMaxime Ripard  *               |  +-+------------+
1285aa288248SMaxime Ripard  *               |    +----------------> MIPI SCLK
1286aa288248SMaxime Ripard  *               |    +  +-----+
1287aa288248SMaxime Ripard  *               |    +->| / 2 |-------> MIPI BIT CLK
1288aa288248SMaxime Ripard  *               |       +-----+
1289aa288248SMaxime Ripard  *               |  +--------------+
1290aa288248SMaxime Ripard  *               +->| PLL Root Div | - reg 0x3037, bit 4
1291aa288248SMaxime Ripard  *                  +-+------------+
1292aa288248SMaxime Ripard  *                    |  +---------+
12934c85f628SPaul Kocialkowski  *                    +->| Bit Div | - reg 0x3034, bits 0-3
1294aa288248SMaxime Ripard  *                       +-+-------+
1295aa288248SMaxime Ripard  *                         |  +-------------+
1296aa288248SMaxime Ripard  *                         +->| SCLK Div    | - reg 0x3108, bits 0-1
1297aa288248SMaxime Ripard  *                         |  +-+-----------+
1298aa288248SMaxime Ripard  *                         |    +---------------> SCLK
1299aa288248SMaxime Ripard  *                         |  +-------------+
1300aa288248SMaxime Ripard  *                         +->| SCLK 2X Div | - reg 0x3108, bits 2-3
1301aa288248SMaxime Ripard  *                         |  +-+-----------+
1302aa288248SMaxime Ripard  *                         |    +---------------> SCLK 2X
1303aa288248SMaxime Ripard  *                         |  +-------------+
1304aa288248SMaxime Ripard  *                         +->| PCLK Div    | - reg 0x3108, bits 4-5
1305aa288248SMaxime Ripard  *                            ++------------+
1306aa288248SMaxime Ripard  *                             +  +-----------+
1307aa288248SMaxime Ripard  *                             +->|   P_DIV   | - reg 0x3035, bits 0-3
1308aa288248SMaxime Ripard  *                                +-----+-----+
1309aa288248SMaxime Ripard  *                                       +------------> PCLK
1310aa288248SMaxime Ripard  *
13116c957ed7SJacopo Mondi  * There seems to be also constraints:
1312aa288248SMaxime Ripard  *  - the PLL pre-divider output rate should be in the 4-27MHz range
1313aa288248SMaxime Ripard  *  - the PLL multiplier output rate should be in the 500-1000MHz range
1314aa288248SMaxime Ripard  *  - PCLK >= SCLK * 2 in YUV, >= SCLK in Raw or JPEG
1315aa288248SMaxime Ripard  */
1316aa288248SMaxime Ripard 
1317aa288248SMaxime Ripard /*
1318aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1319aa288248SMaxime Ripard  * set to 3 in the vendor kernels.
1320aa288248SMaxime Ripard  */
1321aa288248SMaxime Ripard #define OV5640_PLL_PREDIV	3
1322aa288248SMaxime Ripard 
1323aa288248SMaxime Ripard #define OV5640_PLL_MULT_MIN	4
1324aa288248SMaxime Ripard #define OV5640_PLL_MULT_MAX	252
1325aa288248SMaxime Ripard 
1326aa288248SMaxime Ripard /*
1327aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 16, but the value is
1328aa288248SMaxime Ripard  * always set to either 1 or 2 in the vendor kernels.
1329aa288248SMaxime Ripard  */
1330aa288248SMaxime Ripard #define OV5640_SYSDIV_MIN	1
1331aa288248SMaxime Ripard #define OV5640_SYSDIV_MAX	16
1332aa288248SMaxime Ripard 
1333aa288248SMaxime Ripard /*
1334aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 2, but the value is always
1335aa288248SMaxime Ripard  * set to 2 in the vendor kernels.
1336aa288248SMaxime Ripard  */
1337aa288248SMaxime Ripard #define OV5640_PLL_ROOT_DIV			2
1338aa288248SMaxime Ripard #define OV5640_PLL_CTRL3_PLL_ROOT_DIV_2		BIT(4)
1339aa288248SMaxime Ripard 
1340aa288248SMaxime Ripard /*
1341aa288248SMaxime Ripard  * We only supports 8-bit formats at the moment
1342aa288248SMaxime Ripard  */
1343aa288248SMaxime Ripard #define OV5640_BIT_DIV				2
1344aa288248SMaxime Ripard #define OV5640_PLL_CTRL0_MIPI_MODE_8BIT		0x08
1345aa288248SMaxime Ripard 
1346aa288248SMaxime Ripard /*
1347aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1348aa288248SMaxime Ripard  * set to 2 in the vendor kernels.
1349aa288248SMaxime Ripard  */
1350aa288248SMaxime Ripard #define OV5640_SCLK_ROOT_DIV	2
1351aa288248SMaxime Ripard 
1352aa288248SMaxime Ripard /*
1353aa288248SMaxime Ripard  * This is hardcoded so that the consistency is maintained between SCLK and
1354aa288248SMaxime Ripard  * SCLK 2x.
1355aa288248SMaxime Ripard  */
1356aa288248SMaxime Ripard #define OV5640_SCLK2X_ROOT_DIV (OV5640_SCLK_ROOT_DIV / 2)
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 1 in the vendor kernels.
1361aa288248SMaxime Ripard  */
1362aa288248SMaxime Ripard #define OV5640_PCLK_ROOT_DIV			1
1363aa288248SMaxime Ripard #define OV5640_PLL_SYS_ROOT_DIVIDER_BYPASS	0x00
1364aa288248SMaxime Ripard 
1365aa288248SMaxime Ripard static unsigned long ov5640_compute_sys_clk(struct ov5640_dev *sensor,
1366aa288248SMaxime Ripard 					    u8 pll_prediv, u8 pll_mult,
1367aa288248SMaxime Ripard 					    u8 sysdiv)
1368aa288248SMaxime Ripard {
1369aa288248SMaxime Ripard 	unsigned long sysclk = sensor->xclk_freq / pll_prediv * pll_mult;
1370aa288248SMaxime Ripard 
1371aa288248SMaxime Ripard 	/* PLL1 output cannot exceed 1GHz. */
1372aa288248SMaxime Ripard 	if (sysclk / 1000000 > 1000)
1373aa288248SMaxime Ripard 		return 0;
1374aa288248SMaxime Ripard 
1375aa288248SMaxime Ripard 	return sysclk / sysdiv;
1376aa288248SMaxime Ripard }
1377aa288248SMaxime Ripard 
1378aa288248SMaxime Ripard static unsigned long ov5640_calc_sys_clk(struct ov5640_dev *sensor,
1379aa288248SMaxime Ripard 					 unsigned long rate,
1380aa288248SMaxime Ripard 					 u8 *pll_prediv, u8 *pll_mult,
1381aa288248SMaxime Ripard 					 u8 *sysdiv)
1382aa288248SMaxime Ripard {
1383aa288248SMaxime Ripard 	unsigned long best = ~0;
1384aa288248SMaxime Ripard 	u8 best_sysdiv = 1, best_mult = 1;
1385aa288248SMaxime Ripard 	u8 _sysdiv, _pll_mult;
1386aa288248SMaxime Ripard 
1387aa288248SMaxime Ripard 	for (_sysdiv = OV5640_SYSDIV_MIN;
1388aa288248SMaxime Ripard 	     _sysdiv <= OV5640_SYSDIV_MAX;
1389aa288248SMaxime Ripard 	     _sysdiv++) {
1390aa288248SMaxime Ripard 		for (_pll_mult = OV5640_PLL_MULT_MIN;
1391aa288248SMaxime Ripard 		     _pll_mult <= OV5640_PLL_MULT_MAX;
1392aa288248SMaxime Ripard 		     _pll_mult++) {
1393aa288248SMaxime Ripard 			unsigned long _rate;
1394aa288248SMaxime Ripard 
1395aa288248SMaxime Ripard 			/*
1396aa288248SMaxime Ripard 			 * The PLL multiplier cannot be odd if above
1397aa288248SMaxime Ripard 			 * 127.
1398aa288248SMaxime Ripard 			 */
1399aa288248SMaxime Ripard 			if (_pll_mult > 127 && (_pll_mult % 2))
1400aa288248SMaxime Ripard 				continue;
1401aa288248SMaxime Ripard 
1402aa288248SMaxime Ripard 			_rate = ov5640_compute_sys_clk(sensor,
1403aa288248SMaxime Ripard 						       OV5640_PLL_PREDIV,
1404aa288248SMaxime Ripard 						       _pll_mult, _sysdiv);
1405aa288248SMaxime Ripard 
1406aa288248SMaxime Ripard 			/*
1407aa288248SMaxime Ripard 			 * We have reached the maximum allowed PLL1 output,
1408aa288248SMaxime Ripard 			 * increase sysdiv.
1409aa288248SMaxime Ripard 			 */
14102e3df204SAdam Ford 			if (!_rate)
1411aa288248SMaxime Ripard 				break;
1412aa288248SMaxime Ripard 
1413aa288248SMaxime Ripard 			/*
1414aa288248SMaxime Ripard 			 * Prefer rates above the expected clock rate than
1415aa288248SMaxime Ripard 			 * below, even if that means being less precise.
1416aa288248SMaxime Ripard 			 */
1417aa288248SMaxime Ripard 			if (_rate < rate)
1418aa288248SMaxime Ripard 				continue;
1419aa288248SMaxime Ripard 
1420aa288248SMaxime Ripard 			if (abs(rate - _rate) < abs(rate - best)) {
1421aa288248SMaxime Ripard 				best = _rate;
1422aa288248SMaxime Ripard 				best_sysdiv = _sysdiv;
1423aa288248SMaxime Ripard 				best_mult = _pll_mult;
1424aa288248SMaxime Ripard 			}
1425aa288248SMaxime Ripard 
1426aa288248SMaxime Ripard 			if (_rate == rate)
1427aa288248SMaxime Ripard 				goto out;
1428aa288248SMaxime Ripard 		}
1429aa288248SMaxime Ripard 	}
1430aa288248SMaxime Ripard 
1431aa288248SMaxime Ripard out:
1432aa288248SMaxime Ripard 	*sysdiv = best_sysdiv;
1433aa288248SMaxime Ripard 	*pll_prediv = OV5640_PLL_PREDIV;
1434aa288248SMaxime Ripard 	*pll_mult = best_mult;
1435aa288248SMaxime Ripard 
1436aa288248SMaxime Ripard 	return best;
1437aa288248SMaxime Ripard }
1438aa288248SMaxime Ripard 
1439aa288248SMaxime Ripard /*
1440aa288248SMaxime Ripard  * ov5640_set_mipi_pclk() - Calculate the clock tree configuration values
1441aa288248SMaxime Ripard  *			    for the MIPI CSI-2 output.
1442aa288248SMaxime Ripard  */
14436c957ed7SJacopo Mondi static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor)
1444aa288248SMaxime Ripard {
14456c957ed7SJacopo Mondi 	u8 bit_div, mipi_div, pclk_div, sclk_div, sclk2x_div, root_div;
1446aa288248SMaxime Ripard 	u8 prediv, mult, sysdiv;
14476c957ed7SJacopo Mondi 	unsigned long link_freq;
14486c957ed7SJacopo Mondi 	unsigned long sysclk;
14496c957ed7SJacopo Mondi 	u8 pclk_period;
14506c957ed7SJacopo Mondi 	u32 sample_rate;
14516c957ed7SJacopo Mondi 	u32 num_lanes;
1452aa288248SMaxime Ripard 	int ret;
1453aa288248SMaxime Ripard 
14546c957ed7SJacopo Mondi 	/* Use the link freq computed at ov5640_update_pixel_rate() time. */
14556c957ed7SJacopo Mondi 	link_freq = sensor->current_link_freq;
14566c957ed7SJacopo Mondi 
1457aa288248SMaxime Ripard 	/*
14586c957ed7SJacopo Mondi 	 * - mipi_div - Additional divider for the MIPI lane clock.
14596c957ed7SJacopo Mondi 	 *
14606c957ed7SJacopo Mondi 	 * Higher link frequencies would make sysclk > 1GHz.
14616c957ed7SJacopo Mondi 	 * Keep the sysclk low and do not divide in the MIPI domain.
1462aa288248SMaxime Ripard 	 */
14636c957ed7SJacopo Mondi 	if (link_freq > OV5640_LINK_RATE_MAX)
14646c957ed7SJacopo Mondi 		mipi_div = 1;
1465aa288248SMaxime Ripard 	else
14666c957ed7SJacopo Mondi 		mipi_div = 2;
1467aa288248SMaxime Ripard 
14686c957ed7SJacopo Mondi 	sysclk = link_freq * mipi_div;
14696c957ed7SJacopo Mondi 	ov5640_calc_sys_clk(sensor, sysclk, &prediv, &mult, &sysdiv);
1470aa288248SMaxime Ripard 
14716c957ed7SJacopo Mondi 	/*
14726c957ed7SJacopo Mondi 	 * Adjust PLL parameters to maintain the MIPI_SCLK-to-PCLK ratio.
14736c957ed7SJacopo Mondi 	 *
14746c957ed7SJacopo Mondi 	 * - root_div = 2 (fixed)
14756c957ed7SJacopo Mondi 	 * - bit_div : MIPI 8-bit = 2; MIPI 10-bit = 2.5
14766c957ed7SJacopo Mondi 	 * - pclk_div = 1 (fixed)
14776c957ed7SJacopo Mondi 	 * - p_div  = (2 lanes ? mipi_div : 2 * mipi_div)
14786c957ed7SJacopo Mondi 	 *
14796c957ed7SJacopo Mondi 	 * This results in the following MIPI_SCLK depending on the number
14806c957ed7SJacopo Mondi 	 * of lanes:
14816c957ed7SJacopo Mondi 	 *
14826c957ed7SJacopo Mondi 	 * - 2 lanes: MIPI_SCLK = (4 or 5) * PCLK
14836c957ed7SJacopo Mondi 	 * - 1 lanes: MIPI_SCLK = (8 or 10) * PCLK
14846c957ed7SJacopo Mondi 	 */
14856c957ed7SJacopo Mondi 	root_div = OV5640_PLL_CTRL3_PLL_ROOT_DIV_2;
14866c957ed7SJacopo Mondi 	bit_div =  OV5640_PLL_CTRL0_MIPI_MODE_8BIT;
14876c957ed7SJacopo Mondi 	pclk_div = ilog2(OV5640_PCLK_ROOT_DIV);
1488aa288248SMaxime Ripard 
14896c957ed7SJacopo Mondi 	/*
14906c957ed7SJacopo Mondi 	 * Scaler clock:
14916c957ed7SJacopo Mondi 	 * - YUV: PCLK >= 2 * SCLK
14926c957ed7SJacopo Mondi 	 * - RAW or JPEG: PCLK >= SCLK
14936c957ed7SJacopo Mondi 	 * - sclk2x_div = sclk_div / 2
14946c957ed7SJacopo Mondi 	 */
14956c957ed7SJacopo Mondi 	sclk_div = ilog2(OV5640_SCLK_ROOT_DIV);
14966c957ed7SJacopo Mondi 	sclk2x_div = ilog2(OV5640_SCLK2X_ROOT_DIV);
14976c957ed7SJacopo Mondi 
14986c957ed7SJacopo Mondi 	/*
14996c957ed7SJacopo Mondi 	 * Set the pixel clock period expressed in ns with 1-bit decimal
15006c957ed7SJacopo Mondi 	 * (0x01=0.5ns).
15016c957ed7SJacopo Mondi 	 *
15026c957ed7SJacopo Mondi 	 * The register is very briefly documented. In the OV5645 datasheet it
15036c957ed7SJacopo Mondi 	 * is described as (2 * pclk period), and from testing it seems the
15046c957ed7SJacopo Mondi 	 * actual definition is 2 * 8-bit sample period.
15056c957ed7SJacopo Mondi 	 *
15066c957ed7SJacopo Mondi 	 * 2 * sample_period = (mipi_clk * 2 * num_lanes / bpp) * (bpp / 8) / 2
15076c957ed7SJacopo Mondi 	 */
15086c957ed7SJacopo Mondi 	num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes;
15096c957ed7SJacopo Mondi 	sample_rate = (link_freq * mipi_div * num_lanes * 2) / 16;
15106c957ed7SJacopo Mondi 	pclk_period = 2000000000UL / sample_rate;
15116c957ed7SJacopo Mondi 
15126c957ed7SJacopo Mondi 	/* Program the clock tree registers. */
15136c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0, 0x0f, bit_div);
15146c957ed7SJacopo Mondi 	if (ret)
15156c957ed7SJacopo Mondi 		return ret;
15166c957ed7SJacopo Mondi 
15176c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, 0xff,
15186c957ed7SJacopo Mondi 			     (sysdiv << 4) | mipi_div);
1519aa288248SMaxime Ripard 	if (ret)
1520aa288248SMaxime Ripard 		return ret;
1521aa288248SMaxime Ripard 
1522aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2, 0xff, mult);
1523aa288248SMaxime Ripard 	if (ret)
1524aa288248SMaxime Ripard 		return ret;
1525aa288248SMaxime Ripard 
15266c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3, 0x1f,
15276c957ed7SJacopo Mondi 			     root_div | prediv);
1528aa288248SMaxime Ripard 	if (ret)
1529aa288248SMaxime Ripard 		return ret;
1530aa288248SMaxime Ripard 
15316c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
15326c957ed7SJacopo Mondi 			     (pclk_div << 4) | (sclk2x_div << 2) | sclk_div);
15336c957ed7SJacopo Mondi 	if (ret)
15346c957ed7SJacopo Mondi 		return ret;
15356c957ed7SJacopo Mondi 
15366c957ed7SJacopo Mondi 	return ov5640_write_reg(sensor, OV5640_REG_PCLK_PERIOD, pclk_period);
15376c957ed7SJacopo Mondi }
15386c957ed7SJacopo Mondi 
15396c957ed7SJacopo Mondi static u32 ov5640_calc_pixel_rate(struct ov5640_dev *sensor)
15406c957ed7SJacopo Mondi {
15413145efcdSJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
15425113d5b3SJacopo Mondi 	const struct ov5640_timings *timings = &mode->dvp_timings;
15436c957ed7SJacopo Mondi 	u32 rate;
15446c957ed7SJacopo Mondi 
15455113d5b3SJacopo Mondi 	rate = timings->htot * (timings->crop.height + timings->vblank_def);
15466c957ed7SJacopo Mondi 	rate *= ov5640_framerates[sensor->current_fr];
15476c957ed7SJacopo Mondi 
15486c957ed7SJacopo Mondi 	return rate;
1549aa288248SMaxime Ripard }
1550aa288248SMaxime Ripard 
1551aa288248SMaxime Ripard static unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor,
1552aa288248SMaxime Ripard 				      unsigned long rate,
1553aa288248SMaxime Ripard 				      u8 *pll_prediv, u8 *pll_mult, u8 *sysdiv,
1554aa288248SMaxime Ripard 				      u8 *pll_rdiv, u8 *bit_div, u8 *pclk_div)
1555aa288248SMaxime Ripard {
1556aa288248SMaxime Ripard 	unsigned long _rate = rate * OV5640_PLL_ROOT_DIV * OV5640_BIT_DIV *
1557aa288248SMaxime Ripard 				OV5640_PCLK_ROOT_DIV;
1558aa288248SMaxime Ripard 
1559aa288248SMaxime Ripard 	_rate = ov5640_calc_sys_clk(sensor, _rate, pll_prediv, pll_mult,
1560aa288248SMaxime Ripard 				    sysdiv);
1561aa288248SMaxime Ripard 	*pll_rdiv = OV5640_PLL_ROOT_DIV;
1562aa288248SMaxime Ripard 	*bit_div = OV5640_BIT_DIV;
1563aa288248SMaxime Ripard 	*pclk_div = OV5640_PCLK_ROOT_DIV;
1564aa288248SMaxime Ripard 
1565aa288248SMaxime Ripard 	return _rate / *pll_rdiv / *bit_div / *pclk_div;
1566aa288248SMaxime Ripard }
1567aa288248SMaxime Ripard 
15686c957ed7SJacopo Mondi static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor)
1569aa288248SMaxime Ripard {
1570aa288248SMaxime Ripard 	u8 prediv, mult, sysdiv, pll_rdiv, bit_div, pclk_div;
15716c957ed7SJacopo Mondi 	u32 rate;
1572aa288248SMaxime Ripard 	int ret;
1573aa288248SMaxime Ripard 
15746c957ed7SJacopo Mondi 	rate = ov5640_calc_pixel_rate(sensor);
1575a89f14bbSJacopo Mondi 	rate *= ov5640_code_to_bpp(sensor, sensor->fmt.code);
15766c957ed7SJacopo Mondi 	rate /= sensor->ep.bus.parallel.bus_width;
15776c957ed7SJacopo Mondi 
1578aa288248SMaxime Ripard 	ov5640_calc_pclk(sensor, rate, &prediv, &mult, &sysdiv, &pll_rdiv,
1579aa288248SMaxime Ripard 			 &bit_div, &pclk_div);
1580aa288248SMaxime Ripard 
1581aa288248SMaxime Ripard 	if (bit_div == 2)
1582aa288248SMaxime Ripard 		bit_div = 8;
1583aa288248SMaxime Ripard 
1584aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0,
1585aa288248SMaxime Ripard 			     0x0f, bit_div);
1586aa288248SMaxime Ripard 	if (ret)
1587aa288248SMaxime Ripard 		return ret;
1588aa288248SMaxime Ripard 
1589aa288248SMaxime Ripard 	/*
1590aa288248SMaxime Ripard 	 * We need to set sysdiv according to the clock, and to clear
1591aa288248SMaxime Ripard 	 * the MIPI divider.
1592aa288248SMaxime Ripard 	 */
1593aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1,
1594aa288248SMaxime Ripard 			     0xff, sysdiv << 4);
1595aa288248SMaxime Ripard 	if (ret)
1596aa288248SMaxime Ripard 		return ret;
1597aa288248SMaxime Ripard 
1598aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2,
1599aa288248SMaxime Ripard 			     0xff, mult);
1600aa288248SMaxime Ripard 	if (ret)
1601aa288248SMaxime Ripard 		return ret;
1602aa288248SMaxime Ripard 
1603aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3,
1604aa288248SMaxime Ripard 			     0x1f, prediv | ((pll_rdiv - 1) << 4));
1605aa288248SMaxime Ripard 	if (ret)
1606aa288248SMaxime Ripard 		return ret;
1607aa288248SMaxime Ripard 
1608aa288248SMaxime Ripard 	return ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x30,
1609aa288248SMaxime Ripard 			      (ilog2(pclk_div) << 4));
1610aa288248SMaxime Ripard }
1611aa288248SMaxime Ripard 
16127cb013b1SChen-Yu Tsai /* set JPEG framing sizes */
16137cb013b1SChen-Yu Tsai static int ov5640_set_jpeg_timings(struct ov5640_dev *sensor,
16147cb013b1SChen-Yu Tsai 				   const struct ov5640_mode_info *mode)
16157cb013b1SChen-Yu Tsai {
16167cb013b1SChen-Yu Tsai 	int ret;
16177cb013b1SChen-Yu Tsai 
16182b5c18f9SChen-Yu Tsai 	/*
16192b5c18f9SChen-Yu Tsai 	 * compression mode 3 timing
16202b5c18f9SChen-Yu Tsai 	 *
16212b5c18f9SChen-Yu Tsai 	 * Data is transmitted with programmable width (VFIFO_HSIZE).
16222b5c18f9SChen-Yu Tsai 	 * No padding done. Last line may have less data. Varying
16232b5c18f9SChen-Yu Tsai 	 * number of lines per frame, depending on amount of data.
16242b5c18f9SChen-Yu Tsai 	 */
16252b5c18f9SChen-Yu Tsai 	ret = ov5640_mod_reg(sensor, OV5640_REG_JPG_MODE_SELECT, 0x7, 0x3);
16262b5c18f9SChen-Yu Tsai 	if (ret < 0)
16272b5c18f9SChen-Yu Tsai 		return ret;
16282b5c18f9SChen-Yu Tsai 
16295113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_VFIFO_HSIZE, mode->width);
16307cb013b1SChen-Yu Tsai 	if (ret < 0)
16317cb013b1SChen-Yu Tsai 		return ret;
16327cb013b1SChen-Yu Tsai 
16335113d5b3SJacopo Mondi 	return ov5640_write_reg16(sensor, OV5640_REG_VFIFO_VSIZE, mode->height);
16347cb013b1SChen-Yu Tsai }
16357cb013b1SChen-Yu Tsai 
163619a81c14SSteve Longerbeam /* download ov5640 settings to sensor through i2c */
1637bad1774eSJacopo Mondi static int ov5640_set_timings(struct ov5640_dev *sensor,
1638bad1774eSJacopo Mondi 			      const struct ov5640_mode_info *mode)
1639bad1774eSJacopo Mondi {
16405113d5b3SJacopo Mondi 	const struct ov5640_timings *timings;
16415113d5b3SJacopo Mondi 	const struct v4l2_rect *analog_crop;
16425113d5b3SJacopo Mondi 	const struct v4l2_rect *crop;
1643bad1774eSJacopo Mondi 	int ret;
1644bad1774eSJacopo Mondi 
16457cb013b1SChen-Yu Tsai 	if (sensor->fmt.code == MEDIA_BUS_FMT_JPEG_1X8) {
16467cb013b1SChen-Yu Tsai 		ret = ov5640_set_jpeg_timings(sensor, mode);
16477cb013b1SChen-Yu Tsai 		if (ret < 0)
16487cb013b1SChen-Yu Tsai 			return ret;
16497cb013b1SChen-Yu Tsai 	}
16507cb013b1SChen-Yu Tsai 
16512de6bb97SJacopo Mondi 	timings = ov5640_timings(sensor, mode);
16525113d5b3SJacopo Mondi 	analog_crop = &timings->analog_crop;
16535113d5b3SJacopo Mondi 	crop = &timings->crop;
16545113d5b3SJacopo Mondi 
16553145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HS,
16563145efcdSJacopo Mondi 				 analog_crop->left);
1657bad1774eSJacopo Mondi 	if (ret < 0)
1658bad1774eSJacopo Mondi 		return ret;
1659bad1774eSJacopo Mondi 
16603145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VS,
16613145efcdSJacopo Mondi 				 analog_crop->top);
16623145efcdSJacopo Mondi 	if (ret < 0)
16633145efcdSJacopo Mondi 		return ret;
16643145efcdSJacopo Mondi 
16653145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HW,
16663145efcdSJacopo Mondi 				 analog_crop->left + analog_crop->width - 1);
16673145efcdSJacopo Mondi 	if (ret < 0)
16683145efcdSJacopo Mondi 		return ret;
16693145efcdSJacopo Mondi 
16703145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VH,
16713145efcdSJacopo Mondi 				 analog_crop->top + analog_crop->height - 1);
16723145efcdSJacopo Mondi 	if (ret < 0)
16733145efcdSJacopo Mondi 		return ret;
16743145efcdSJacopo Mondi 
16753145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HOFFS, crop->left);
16763145efcdSJacopo Mondi 	if (ret < 0)
16773145efcdSJacopo Mondi 		return ret;
16783145efcdSJacopo Mondi 
16793145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VOFFS, crop->top);
16803145efcdSJacopo Mondi 	if (ret < 0)
16813145efcdSJacopo Mondi 		return ret;
16823145efcdSJacopo Mondi 
16835113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->width);
16843145efcdSJacopo Mondi 	if (ret < 0)
16853145efcdSJacopo Mondi 		return ret;
16863145efcdSJacopo Mondi 
16875113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, mode->height);
1688bad1774eSJacopo Mondi 	if (ret < 0)
1689bad1774eSJacopo Mondi 		return ret;
1690bad1774eSJacopo Mondi 
16915113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, timings->htot);
1692bad1774eSJacopo Mondi 	if (ret < 0)
1693bad1774eSJacopo Mondi 		return ret;
1694bad1774eSJacopo Mondi 
16953145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS,
16965113d5b3SJacopo Mondi 				 mode->height + timings->vblank_def);
16973145efcdSJacopo Mondi 	if (ret < 0)
16983145efcdSJacopo Mondi 		return ret;
16993145efcdSJacopo Mondi 
17003145efcdSJacopo Mondi 	return 0;
1701bad1774eSJacopo Mondi }
1702bad1774eSJacopo Mondi 
1703e4359019SJacopo Mondi static void ov5640_load_regs(struct ov5640_dev *sensor,
1704e4359019SJacopo Mondi 			     const struct reg_value *regs, unsigned int regnum)
170519a81c14SSteve Longerbeam {
170619a81c14SSteve Longerbeam 	unsigned int i;
170719a81c14SSteve Longerbeam 	u32 delay_ms;
170819a81c14SSteve Longerbeam 	u16 reg_addr;
170919a81c14SSteve Longerbeam 	u8 mask, val;
171019a81c14SSteve Longerbeam 	int ret = 0;
171119a81c14SSteve Longerbeam 
1712e4359019SJacopo Mondi 	for (i = 0; i < regnum; ++i, ++regs) {
171319a81c14SSteve Longerbeam 		delay_ms = regs->delay_ms;
171419a81c14SSteve Longerbeam 		reg_addr = regs->reg_addr;
171519a81c14SSteve Longerbeam 		val = regs->val;
171619a81c14SSteve Longerbeam 		mask = regs->mask;
171719a81c14SSteve Longerbeam 
17183b987d70SLad Prabhakar 		/* remain in power down mode for DVP */
17193b987d70SLad Prabhakar 		if (regs->reg_addr == OV5640_REG_SYS_CTRL0 &&
17203b987d70SLad Prabhakar 		    val == OV5640_REG_SYS_CTRL0_SW_PWUP &&
17218e823f5cSJacopo Mondi 		    !ov5640_is_csi2(sensor))
17223b987d70SLad Prabhakar 			continue;
17233b987d70SLad Prabhakar 
172419a81c14SSteve Longerbeam 		if (mask)
172519a81c14SSteve Longerbeam 			ret = ov5640_mod_reg(sensor, reg_addr, mask, val);
172619a81c14SSteve Longerbeam 		else
172719a81c14SSteve Longerbeam 			ret = ov5640_write_reg(sensor, reg_addr, val);
172819a81c14SSteve Longerbeam 		if (ret)
172919a81c14SSteve Longerbeam 			break;
173019a81c14SSteve Longerbeam 
173119a81c14SSteve Longerbeam 		if (delay_ms)
173219a81c14SSteve Longerbeam 			usleep_range(1000 * delay_ms, 1000 * delay_ms + 100);
173319a81c14SSteve Longerbeam 	}
173419a81c14SSteve Longerbeam }
173519a81c14SSteve Longerbeam 
1736dc29a1c1SHugues Fruchet static int ov5640_set_autoexposure(struct ov5640_dev *sensor, bool on)
1737dc29a1c1SHugues Fruchet {
1738dc29a1c1SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
1739dc29a1c1SHugues Fruchet 			      BIT(0), on ? 0 : BIT(0));
1740dc29a1c1SHugues Fruchet }
1741dc29a1c1SHugues Fruchet 
174219a81c14SSteve Longerbeam /* read exposure, in number of line periods */
174319a81c14SSteve Longerbeam static int ov5640_get_exposure(struct ov5640_dev *sensor)
174419a81c14SSteve Longerbeam {
174519a81c14SSteve Longerbeam 	int exp, ret;
174619a81c14SSteve Longerbeam 	u8 temp;
174719a81c14SSteve Longerbeam 
174819a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_HI, &temp);
174919a81c14SSteve Longerbeam 	if (ret)
175019a81c14SSteve Longerbeam 		return ret;
175119a81c14SSteve Longerbeam 	exp = ((int)temp & 0x0f) << 16;
175219a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_MED, &temp);
175319a81c14SSteve Longerbeam 	if (ret)
175419a81c14SSteve Longerbeam 		return ret;
175519a81c14SSteve Longerbeam 	exp |= ((int)temp << 8);
175619a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_LO, &temp);
175719a81c14SSteve Longerbeam 	if (ret)
175819a81c14SSteve Longerbeam 		return ret;
175919a81c14SSteve Longerbeam 	exp |= (int)temp;
176019a81c14SSteve Longerbeam 
176119a81c14SSteve Longerbeam 	return exp >> 4;
176219a81c14SSteve Longerbeam }
176319a81c14SSteve Longerbeam 
176419a81c14SSteve Longerbeam /* write exposure, given number of line periods */
176519a81c14SSteve Longerbeam static int ov5640_set_exposure(struct ov5640_dev *sensor, u32 exposure)
176619a81c14SSteve Longerbeam {
176719a81c14SSteve Longerbeam 	int ret;
176819a81c14SSteve Longerbeam 
176919a81c14SSteve Longerbeam 	exposure <<= 4;
177019a81c14SSteve Longerbeam 
177119a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor,
177219a81c14SSteve Longerbeam 			       OV5640_REG_AEC_PK_EXPOSURE_LO,
177319a81c14SSteve Longerbeam 			       exposure & 0xff);
177419a81c14SSteve Longerbeam 	if (ret)
177519a81c14SSteve Longerbeam 		return ret;
177619a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor,
177719a81c14SSteve Longerbeam 			       OV5640_REG_AEC_PK_EXPOSURE_MED,
177819a81c14SSteve Longerbeam 			       (exposure >> 8) & 0xff);
177919a81c14SSteve Longerbeam 	if (ret)
178019a81c14SSteve Longerbeam 		return ret;
178119a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor,
178219a81c14SSteve Longerbeam 				OV5640_REG_AEC_PK_EXPOSURE_HI,
178319a81c14SSteve Longerbeam 				(exposure >> 16) & 0x0f);
178419a81c14SSteve Longerbeam }
178519a81c14SSteve Longerbeam 
178619a81c14SSteve Longerbeam static int ov5640_get_gain(struct ov5640_dev *sensor)
178719a81c14SSteve Longerbeam {
178819a81c14SSteve Longerbeam 	u16 gain;
178919a81c14SSteve Longerbeam 	int ret;
179019a81c14SSteve Longerbeam 
179119a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN, &gain);
179219a81c14SSteve Longerbeam 	if (ret)
179319a81c14SSteve Longerbeam 		return ret;
179419a81c14SSteve Longerbeam 
179519a81c14SSteve Longerbeam 	return gain & 0x3ff;
179619a81c14SSteve Longerbeam }
179719a81c14SSteve Longerbeam 
17983cca8ef5SHugues Fruchet static int ov5640_set_gain(struct ov5640_dev *sensor, int gain)
17993cca8ef5SHugues Fruchet {
18003cca8ef5SHugues Fruchet 	return ov5640_write_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN,
18013cca8ef5SHugues Fruchet 				  (u16)gain & 0x3ff);
18023cca8ef5SHugues Fruchet }
18033cca8ef5SHugues Fruchet 
18043cca8ef5SHugues Fruchet static int ov5640_set_autogain(struct ov5640_dev *sensor, bool on)
18053cca8ef5SHugues Fruchet {
18063cca8ef5SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
18073cca8ef5SHugues Fruchet 			      BIT(1), on ? 0 : BIT(1));
18083cca8ef5SHugues Fruchet }
18093cca8ef5SHugues Fruchet 
1810f22996dbSHugues Fruchet static int ov5640_set_stream_dvp(struct ov5640_dev *sensor, bool on)
1811f22996dbSHugues Fruchet {
18123b987d70SLad Prabhakar 	return ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0, on ?
18133b987d70SLad Prabhakar 				OV5640_REG_SYS_CTRL0_SW_PWUP :
18143b987d70SLad Prabhakar 				OV5640_REG_SYS_CTRL0_SW_PWDN);
1815f22996dbSHugues Fruchet }
1816f22996dbSHugues Fruchet 
1817f22996dbSHugues Fruchet static int ov5640_set_stream_mipi(struct ov5640_dev *sensor, bool on)
181819a81c14SSteve Longerbeam {
181919a81c14SSteve Longerbeam 	int ret;
182019a81c14SSteve Longerbeam 
1821aa4bb8b8SJacopo Mondi 	/*
1822aa4bb8b8SJacopo Mondi 	 * Enable/disable the MIPI interface
1823aa4bb8b8SJacopo Mondi 	 *
1824aa4bb8b8SJacopo Mondi 	 * 0x300e = on ? 0x45 : 0x40
1825aa4bb8b8SJacopo Mondi 	 *
1826aa4bb8b8SJacopo Mondi 	 * FIXME: the sensor manual (version 2.03) reports
1827aa4bb8b8SJacopo Mondi 	 * [7:5] = 000  : 1 data lane mode
1828aa4bb8b8SJacopo Mondi 	 * [7:5] = 001  : 2 data lanes mode
1829aa4bb8b8SJacopo Mondi 	 * But this settings do not work, while the following ones
1830aa4bb8b8SJacopo Mondi 	 * have been validated for 2 data lanes mode.
1831aa4bb8b8SJacopo Mondi 	 *
1832aa4bb8b8SJacopo Mondi 	 * [7:5] = 010	: 2 data lanes mode
1833aa4bb8b8SJacopo Mondi 	 * [4] = 0	: Power up MIPI HS Tx
1834aa4bb8b8SJacopo Mondi 	 * [3] = 0	: Power up MIPI LS Rx
1835aa4bb8b8SJacopo Mondi 	 * [2] = 1/0	: MIPI interface enable/disable
1836aa4bb8b8SJacopo Mondi 	 * [1:0] = 01/00: FIXME: 'debug'
1837aa4bb8b8SJacopo Mondi 	 */
1838aa4bb8b8SJacopo Mondi 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00,
1839aa4bb8b8SJacopo Mondi 			       on ? 0x45 : 0x40);
184019a81c14SSteve Longerbeam 	if (ret)
184119a81c14SSteve Longerbeam 		return ret;
184219a81c14SSteve Longerbeam 
184319a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_FRAME_CTRL01,
184419a81c14SSteve Longerbeam 				on ? 0x00 : 0x0f);
184519a81c14SSteve Longerbeam }
184619a81c14SSteve Longerbeam 
184719a81c14SSteve Longerbeam static int ov5640_get_sysclk(struct ov5640_dev *sensor)
184819a81c14SSteve Longerbeam {
184919a81c14SSteve Longerbeam 	 /* calculate sysclk */
185019a81c14SSteve Longerbeam 	u32 xvclk = sensor->xclk_freq / 10000;
185119a81c14SSteve Longerbeam 	u32 multiplier, prediv, VCO, sysdiv, pll_rdiv;
185219a81c14SSteve Longerbeam 	u32 sclk_rdiv_map[] = {1, 2, 4, 8};
185319a81c14SSteve Longerbeam 	u32 bit_div2x = 1, sclk_rdiv, sysclk;
185419a81c14SSteve Longerbeam 	u8 temp1, temp2;
185519a81c14SSteve Longerbeam 	int ret;
185619a81c14SSteve Longerbeam 
185719a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL0, &temp1);
185819a81c14SSteve Longerbeam 	if (ret)
185919a81c14SSteve Longerbeam 		return ret;
186019a81c14SSteve Longerbeam 	temp2 = temp1 & 0x0f;
186119a81c14SSteve Longerbeam 	if (temp2 == 8 || temp2 == 10)
186219a81c14SSteve Longerbeam 		bit_div2x = temp2 / 2;
186319a81c14SSteve Longerbeam 
186419a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL1, &temp1);
186519a81c14SSteve Longerbeam 	if (ret)
186619a81c14SSteve Longerbeam 		return ret;
186719a81c14SSteve Longerbeam 	sysdiv = temp1 >> 4;
186819a81c14SSteve Longerbeam 	if (sysdiv == 0)
186919a81c14SSteve Longerbeam 		sysdiv = 16;
187019a81c14SSteve Longerbeam 
187119a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL2, &temp1);
187219a81c14SSteve Longerbeam 	if (ret)
187319a81c14SSteve Longerbeam 		return ret;
187419a81c14SSteve Longerbeam 	multiplier = temp1;
187519a81c14SSteve Longerbeam 
187619a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL3, &temp1);
187719a81c14SSteve Longerbeam 	if (ret)
187819a81c14SSteve Longerbeam 		return ret;
187919a81c14SSteve Longerbeam 	prediv = temp1 & 0x0f;
188019a81c14SSteve Longerbeam 	pll_rdiv = ((temp1 >> 4) & 0x01) + 1;
188119a81c14SSteve Longerbeam 
188219a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, &temp1);
188319a81c14SSteve Longerbeam 	if (ret)
188419a81c14SSteve Longerbeam 		return ret;
188519a81c14SSteve Longerbeam 	temp2 = temp1 & 0x03;
188619a81c14SSteve Longerbeam 	sclk_rdiv = sclk_rdiv_map[temp2];
188719a81c14SSteve Longerbeam 
188819a81c14SSteve Longerbeam 	if (!prediv || !sysdiv || !pll_rdiv || !bit_div2x)
188919a81c14SSteve Longerbeam 		return -EINVAL;
189019a81c14SSteve Longerbeam 
189119a81c14SSteve Longerbeam 	VCO = xvclk * multiplier / prediv;
189219a81c14SSteve Longerbeam 
189319a81c14SSteve Longerbeam 	sysclk = VCO / sysdiv / pll_rdiv * 2 / bit_div2x / sclk_rdiv;
189419a81c14SSteve Longerbeam 
189519a81c14SSteve Longerbeam 	return sysclk;
189619a81c14SSteve Longerbeam }
189719a81c14SSteve Longerbeam 
189819a81c14SSteve Longerbeam static int ov5640_set_night_mode(struct ov5640_dev *sensor)
189919a81c14SSteve Longerbeam {
190019a81c14SSteve Longerbeam 	 /* read HTS from register settings */
190119a81c14SSteve Longerbeam 	u8 mode;
190219a81c14SSteve Longerbeam 	int ret;
190319a81c14SSteve Longerbeam 
190419a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_CTRL00, &mode);
190519a81c14SSteve Longerbeam 	if (ret)
190619a81c14SSteve Longerbeam 		return ret;
190719a81c14SSteve Longerbeam 	mode &= 0xfb;
190819a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL00, mode);
190919a81c14SSteve Longerbeam }
191019a81c14SSteve Longerbeam 
191119a81c14SSteve Longerbeam static int ov5640_get_hts(struct ov5640_dev *sensor)
191219a81c14SSteve Longerbeam {
191319a81c14SSteve Longerbeam 	/* read HTS from register settings */
191419a81c14SSteve Longerbeam 	u16 hts;
191519a81c14SSteve Longerbeam 	int ret;
191619a81c14SSteve Longerbeam 
191719a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_HTS, &hts);
191819a81c14SSteve Longerbeam 	if (ret)
191919a81c14SSteve Longerbeam 		return ret;
192019a81c14SSteve Longerbeam 	return hts;
192119a81c14SSteve Longerbeam }
192219a81c14SSteve Longerbeam 
192319a81c14SSteve Longerbeam static int ov5640_get_vts(struct ov5640_dev *sensor)
192419a81c14SSteve Longerbeam {
192519a81c14SSteve Longerbeam 	u16 vts;
192619a81c14SSteve Longerbeam 	int ret;
192719a81c14SSteve Longerbeam 
192819a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_VTS, &vts);
192919a81c14SSteve Longerbeam 	if (ret)
193019a81c14SSteve Longerbeam 		return ret;
193119a81c14SSteve Longerbeam 	return vts;
193219a81c14SSteve Longerbeam }
193319a81c14SSteve Longerbeam 
193419a81c14SSteve Longerbeam static int ov5640_set_vts(struct ov5640_dev *sensor, int vts)
193519a81c14SSteve Longerbeam {
193619a81c14SSteve Longerbeam 	return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, vts);
193719a81c14SSteve Longerbeam }
193819a81c14SSteve Longerbeam 
193919a81c14SSteve Longerbeam static int ov5640_get_light_freq(struct ov5640_dev *sensor)
194019a81c14SSteve Longerbeam {
194119a81c14SSteve Longerbeam 	/* get banding filter value */
194219a81c14SSteve Longerbeam 	int ret, light_freq = 0;
194319a81c14SSteve Longerbeam 	u8 temp, temp1;
194419a81c14SSteve Longerbeam 
194519a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL01, &temp);
194619a81c14SSteve Longerbeam 	if (ret)
194719a81c14SSteve Longerbeam 		return ret;
194819a81c14SSteve Longerbeam 
194919a81c14SSteve Longerbeam 	if (temp & 0x80) {
195019a81c14SSteve Longerbeam 		/* manual */
195119a81c14SSteve Longerbeam 		ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL00,
195219a81c14SSteve Longerbeam 				      &temp1);
195319a81c14SSteve Longerbeam 		if (ret)
195419a81c14SSteve Longerbeam 			return ret;
195519a81c14SSteve Longerbeam 		if (temp1 & 0x04) {
195619a81c14SSteve Longerbeam 			/* 50Hz */
195719a81c14SSteve Longerbeam 			light_freq = 50;
195819a81c14SSteve Longerbeam 		} else {
195919a81c14SSteve Longerbeam 			/* 60Hz */
196019a81c14SSteve Longerbeam 			light_freq = 60;
196119a81c14SSteve Longerbeam 		}
196219a81c14SSteve Longerbeam 	} else {
196319a81c14SSteve Longerbeam 		/* auto */
196419a81c14SSteve Longerbeam 		ret = ov5640_read_reg(sensor, OV5640_REG_SIGMADELTA_CTRL0C,
196519a81c14SSteve Longerbeam 				      &temp1);
196619a81c14SSteve Longerbeam 		if (ret)
196719a81c14SSteve Longerbeam 			return ret;
196819a81c14SSteve Longerbeam 
196919a81c14SSteve Longerbeam 		if (temp1 & 0x01) {
197019a81c14SSteve Longerbeam 			/* 50Hz */
197119a81c14SSteve Longerbeam 			light_freq = 50;
197219a81c14SSteve Longerbeam 		} else {
197319a81c14SSteve Longerbeam 			/* 60Hz */
197419a81c14SSteve Longerbeam 		}
197519a81c14SSteve Longerbeam 	}
197619a81c14SSteve Longerbeam 
197719a81c14SSteve Longerbeam 	return light_freq;
197819a81c14SSteve Longerbeam }
197919a81c14SSteve Longerbeam 
198019a81c14SSteve Longerbeam static int ov5640_set_bandingfilter(struct ov5640_dev *sensor)
198119a81c14SSteve Longerbeam {
198219a81c14SSteve Longerbeam 	u32 band_step60, max_band60, band_step50, max_band50, prev_vts;
198319a81c14SSteve Longerbeam 	int ret;
198419a81c14SSteve Longerbeam 
198519a81c14SSteve Longerbeam 	/* read preview PCLK */
198619a81c14SSteve Longerbeam 	ret = ov5640_get_sysclk(sensor);
198719a81c14SSteve Longerbeam 	if (ret < 0)
198819a81c14SSteve Longerbeam 		return ret;
198919a81c14SSteve Longerbeam 	if (ret == 0)
199019a81c14SSteve Longerbeam 		return -EINVAL;
199119a81c14SSteve Longerbeam 	sensor->prev_sysclk = ret;
199219a81c14SSteve Longerbeam 	/* read preview HTS */
199319a81c14SSteve Longerbeam 	ret = ov5640_get_hts(sensor);
199419a81c14SSteve Longerbeam 	if (ret < 0)
199519a81c14SSteve Longerbeam 		return ret;
199619a81c14SSteve Longerbeam 	if (ret == 0)
199719a81c14SSteve Longerbeam 		return -EINVAL;
199819a81c14SSteve Longerbeam 	sensor->prev_hts = ret;
199919a81c14SSteve Longerbeam 
200019a81c14SSteve Longerbeam 	/* read preview VTS */
200119a81c14SSteve Longerbeam 	ret = ov5640_get_vts(sensor);
200219a81c14SSteve Longerbeam 	if (ret < 0)
200319a81c14SSteve Longerbeam 		return ret;
200419a81c14SSteve Longerbeam 	prev_vts = ret;
200519a81c14SSteve Longerbeam 
200619a81c14SSteve Longerbeam 	/* calculate banding filter */
200719a81c14SSteve Longerbeam 	/* 60Hz */
200819a81c14SSteve Longerbeam 	band_step60 = sensor->prev_sysclk * 100 / sensor->prev_hts * 100 / 120;
200919a81c14SSteve Longerbeam 	ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B60_STEP, band_step60);
201019a81c14SSteve Longerbeam 	if (ret)
201119a81c14SSteve Longerbeam 		return ret;
201219a81c14SSteve Longerbeam 	if (!band_step60)
201319a81c14SSteve Longerbeam 		return -EINVAL;
201419a81c14SSteve Longerbeam 	max_band60 = (int)((prev_vts - 4) / band_step60);
201519a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0D, max_band60);
201619a81c14SSteve Longerbeam 	if (ret)
201719a81c14SSteve Longerbeam 		return ret;
201819a81c14SSteve Longerbeam 
201919a81c14SSteve Longerbeam 	/* 50Hz */
202019a81c14SSteve Longerbeam 	band_step50 = sensor->prev_sysclk * 100 / sensor->prev_hts;
202119a81c14SSteve Longerbeam 	ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B50_STEP, band_step50);
202219a81c14SSteve Longerbeam 	if (ret)
202319a81c14SSteve Longerbeam 		return ret;
202419a81c14SSteve Longerbeam 	if (!band_step50)
202519a81c14SSteve Longerbeam 		return -EINVAL;
202619a81c14SSteve Longerbeam 	max_band50 = (int)((prev_vts - 4) / band_step50);
202719a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0E, max_band50);
202819a81c14SSteve Longerbeam }
202919a81c14SSteve Longerbeam 
203019a81c14SSteve Longerbeam static int ov5640_set_ae_target(struct ov5640_dev *sensor, int target)
203119a81c14SSteve Longerbeam {
203219a81c14SSteve Longerbeam 	/* stable in high */
203319a81c14SSteve Longerbeam 	u32 fast_high, fast_low;
203419a81c14SSteve Longerbeam 	int ret;
203519a81c14SSteve Longerbeam 
203619a81c14SSteve Longerbeam 	sensor->ae_low = target * 23 / 25;	/* 0.92 */
203719a81c14SSteve Longerbeam 	sensor->ae_high = target * 27 / 25;	/* 1.08 */
203819a81c14SSteve Longerbeam 
203919a81c14SSteve Longerbeam 	fast_high = sensor->ae_high << 1;
204019a81c14SSteve Longerbeam 	if (fast_high > 255)
204119a81c14SSteve Longerbeam 		fast_high = 255;
204219a81c14SSteve Longerbeam 
204319a81c14SSteve Longerbeam 	fast_low = sensor->ae_low >> 1;
204419a81c14SSteve Longerbeam 
204519a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0F, sensor->ae_high);
204619a81c14SSteve Longerbeam 	if (ret)
204719a81c14SSteve Longerbeam 		return ret;
204819a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL10, sensor->ae_low);
204919a81c14SSteve Longerbeam 	if (ret)
205019a81c14SSteve Longerbeam 		return ret;
205119a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1B, sensor->ae_high);
205219a81c14SSteve Longerbeam 	if (ret)
205319a81c14SSteve Longerbeam 		return ret;
205419a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1E, sensor->ae_low);
205519a81c14SSteve Longerbeam 	if (ret)
205619a81c14SSteve Longerbeam 		return ret;
205719a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL11, fast_high);
205819a81c14SSteve Longerbeam 	if (ret)
205919a81c14SSteve Longerbeam 		return ret;
206019a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1F, fast_low);
206119a81c14SSteve Longerbeam }
206219a81c14SSteve Longerbeam 
2063c2c3f42dSHugues Fruchet static int ov5640_get_binning(struct ov5640_dev *sensor)
206419a81c14SSteve Longerbeam {
206519a81c14SSteve Longerbeam 	u8 temp;
206619a81c14SSteve Longerbeam 	int ret;
206719a81c14SSteve Longerbeam 
206819a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_TIMING_TC_REG21, &temp);
206919a81c14SSteve Longerbeam 	if (ret)
207019a81c14SSteve Longerbeam 		return ret;
2071c2c3f42dSHugues Fruchet 
2072c2c3f42dSHugues Fruchet 	return temp & BIT(0);
207319a81c14SSteve Longerbeam }
207419a81c14SSteve Longerbeam 
2075ce85705aSHugues Fruchet static int ov5640_set_binning(struct ov5640_dev *sensor, bool enable)
2076ce85705aSHugues Fruchet {
2077ce85705aSHugues Fruchet 	int ret;
2078ce85705aSHugues Fruchet 
2079ce85705aSHugues Fruchet 	/*
2080ce85705aSHugues Fruchet 	 * TIMING TC REG21:
2081ce85705aSHugues Fruchet 	 * - [0]:	Horizontal binning enable
2082ce85705aSHugues Fruchet 	 */
2083ce85705aSHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
2084ce85705aSHugues Fruchet 			     BIT(0), enable ? BIT(0) : 0);
2085ce85705aSHugues Fruchet 	if (ret)
2086ce85705aSHugues Fruchet 		return ret;
2087ce85705aSHugues Fruchet 	/*
2088ce85705aSHugues Fruchet 	 * TIMING TC REG20:
2089ce85705aSHugues Fruchet 	 * - [0]:	Undocumented, but hardcoded init sequences
2090ce85705aSHugues Fruchet 	 *		are always setting REG21/REG20 bit 0 to same value...
2091ce85705aSHugues Fruchet 	 */
2092ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20,
2093ce85705aSHugues Fruchet 			      BIT(0), enable ? BIT(0) : 0);
2094ce85705aSHugues Fruchet }
2095ce85705aSHugues Fruchet 
209619a81c14SSteve Longerbeam static int ov5640_set_virtual_channel(struct ov5640_dev *sensor)
209719a81c14SSteve Longerbeam {
20988670d70aSHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
209919a81c14SSteve Longerbeam 	u8 temp, channel = virtual_channel;
210019a81c14SSteve Longerbeam 	int ret;
210119a81c14SSteve Longerbeam 
21028670d70aSHugues Fruchet 	if (channel > 3) {
21038670d70aSHugues Fruchet 		dev_err(&client->dev,
21048670d70aSHugues Fruchet 			"%s: wrong virtual_channel parameter, expected (0..3), got %d\n",
21058670d70aSHugues Fruchet 			__func__, channel);
210619a81c14SSteve Longerbeam 		return -EINVAL;
21078670d70aSHugues Fruchet 	}
210819a81c14SSteve Longerbeam 
210919a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_DEBUG_MODE, &temp);
211019a81c14SSteve Longerbeam 	if (ret)
211119a81c14SSteve Longerbeam 		return ret;
211219a81c14SSteve Longerbeam 	temp &= ~(3 << 6);
211319a81c14SSteve Longerbeam 	temp |= (channel << 6);
211419a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_DEBUG_MODE, temp);
211519a81c14SSteve Longerbeam }
211619a81c14SSteve Longerbeam 
211719a81c14SSteve Longerbeam static const struct ov5640_mode_info *
2118b6ae5022SJacopo Mondi ov5640_find_mode(struct ov5640_dev *sensor, int width, int height, bool nearest)
211919a81c14SSteve Longerbeam {
21203c4a7372SHugues Fruchet 	const struct ov5640_mode_info *mode;
212119a81c14SSteve Longerbeam 
2122086c25f8SMaxime Ripard 	mode = v4l2_find_nearest_size(ov5640_mode_data,
2123086c25f8SMaxime Ripard 				      ARRAY_SIZE(ov5640_mode_data),
21245113d5b3SJacopo Mondi 				      width, height, width, height);
212519a81c14SSteve Longerbeam 
21263c4a7372SHugues Fruchet 	if (!mode ||
21273145efcdSJacopo Mondi 	    (!nearest &&
21285113d5b3SJacopo Mondi 	     (mode->width != width || mode->height != height)))
21293c4a7372SHugues Fruchet 		return NULL;
213019a81c14SSteve Longerbeam 
213119a81c14SSteve Longerbeam 	return mode;
213219a81c14SSteve Longerbeam }
213319a81c14SSteve Longerbeam 
213419a81c14SSteve Longerbeam /*
213519a81c14SSteve Longerbeam  * sensor changes between scaling and subsampling, go through
213619a81c14SSteve Longerbeam  * exposure calculation
213719a81c14SSteve Longerbeam  */
213841d8d7f5SHugues Fruchet static int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor,
213941d8d7f5SHugues Fruchet 					 const struct ov5640_mode_info *mode)
214019a81c14SSteve Longerbeam {
214119a81c14SSteve Longerbeam 	u32 prev_shutter, prev_gain16;
214219a81c14SSteve Longerbeam 	u32 cap_shutter, cap_gain16;
214319a81c14SSteve Longerbeam 	u32 cap_sysclk, cap_hts, cap_vts;
214419a81c14SSteve Longerbeam 	u32 light_freq, cap_bandfilt, cap_maxband;
214519a81c14SSteve Longerbeam 	u32 cap_gain16_shutter;
214619a81c14SSteve Longerbeam 	u8 average;
214719a81c14SSteve Longerbeam 	int ret;
214819a81c14SSteve Longerbeam 
214941d8d7f5SHugues Fruchet 	if (!mode->reg_data)
215019a81c14SSteve Longerbeam 		return -EINVAL;
215119a81c14SSteve Longerbeam 
215219a81c14SSteve Longerbeam 	/* read preview shutter */
215319a81c14SSteve Longerbeam 	ret = ov5640_get_exposure(sensor);
215419a81c14SSteve Longerbeam 	if (ret < 0)
215519a81c14SSteve Longerbeam 		return ret;
215619a81c14SSteve Longerbeam 	prev_shutter = ret;
2157c2c3f42dSHugues Fruchet 	ret = ov5640_get_binning(sensor);
215819a81c14SSteve Longerbeam 	if (ret < 0)
215919a81c14SSteve Longerbeam 		return ret;
216019a81c14SSteve Longerbeam 	if (ret && mode->id != OV5640_MODE_720P_1280_720 &&
216119a81c14SSteve Longerbeam 	    mode->id != OV5640_MODE_1080P_1920_1080)
216219a81c14SSteve Longerbeam 		prev_shutter *= 2;
216319a81c14SSteve Longerbeam 
216419a81c14SSteve Longerbeam 	/* read preview gain */
216519a81c14SSteve Longerbeam 	ret = ov5640_get_gain(sensor);
216619a81c14SSteve Longerbeam 	if (ret < 0)
216719a81c14SSteve Longerbeam 		return ret;
216819a81c14SSteve Longerbeam 	prev_gain16 = ret;
216919a81c14SSteve Longerbeam 
217019a81c14SSteve Longerbeam 	/* get average */
217119a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AVG_READOUT, &average);
217219a81c14SSteve Longerbeam 	if (ret)
217319a81c14SSteve Longerbeam 		return ret;
217419a81c14SSteve Longerbeam 
217519a81c14SSteve Longerbeam 	/* turn off night mode for capture */
217619a81c14SSteve Longerbeam 	ret = ov5640_set_night_mode(sensor);
217719a81c14SSteve Longerbeam 	if (ret < 0)
217819a81c14SSteve Longerbeam 		return ret;
217919a81c14SSteve Longerbeam 
218019a81c14SSteve Longerbeam 	/* Write capture setting */
2181e4359019SJacopo Mondi 	ov5640_load_regs(sensor, mode->reg_data, mode->reg_data_size);
2182e4359019SJacopo Mondi 	ret = ov5640_set_timings(sensor, mode);
218319a81c14SSteve Longerbeam 	if (ret < 0)
218419a81c14SSteve Longerbeam 		return ret;
218519a81c14SSteve Longerbeam 
218619a81c14SSteve Longerbeam 	/* read capture VTS */
218719a81c14SSteve Longerbeam 	ret = ov5640_get_vts(sensor);
218819a81c14SSteve Longerbeam 	if (ret < 0)
218919a81c14SSteve Longerbeam 		return ret;
219019a81c14SSteve Longerbeam 	cap_vts = ret;
219119a81c14SSteve Longerbeam 	ret = ov5640_get_hts(sensor);
219219a81c14SSteve Longerbeam 	if (ret < 0)
219319a81c14SSteve Longerbeam 		return ret;
219419a81c14SSteve Longerbeam 	if (ret == 0)
219519a81c14SSteve Longerbeam 		return -EINVAL;
219619a81c14SSteve Longerbeam 	cap_hts = ret;
219719a81c14SSteve Longerbeam 
219819a81c14SSteve Longerbeam 	ret = ov5640_get_sysclk(sensor);
219919a81c14SSteve Longerbeam 	if (ret < 0)
220019a81c14SSteve Longerbeam 		return ret;
220119a81c14SSteve Longerbeam 	if (ret == 0)
220219a81c14SSteve Longerbeam 		return -EINVAL;
220319a81c14SSteve Longerbeam 	cap_sysclk = ret;
220419a81c14SSteve Longerbeam 
220519a81c14SSteve Longerbeam 	/* calculate capture banding filter */
220619a81c14SSteve Longerbeam 	ret = ov5640_get_light_freq(sensor);
220719a81c14SSteve Longerbeam 	if (ret < 0)
220819a81c14SSteve Longerbeam 		return ret;
220919a81c14SSteve Longerbeam 	light_freq = ret;
221019a81c14SSteve Longerbeam 
221119a81c14SSteve Longerbeam 	if (light_freq == 60) {
221219a81c14SSteve Longerbeam 		/* 60Hz */
221319a81c14SSteve Longerbeam 		cap_bandfilt = cap_sysclk * 100 / cap_hts * 100 / 120;
221419a81c14SSteve Longerbeam 	} else {
221519a81c14SSteve Longerbeam 		/* 50Hz */
221619a81c14SSteve Longerbeam 		cap_bandfilt = cap_sysclk * 100 / cap_hts;
221719a81c14SSteve Longerbeam 	}
221819a81c14SSteve Longerbeam 
221919a81c14SSteve Longerbeam 	if (!sensor->prev_sysclk) {
222019a81c14SSteve Longerbeam 		ret = ov5640_get_sysclk(sensor);
222119a81c14SSteve Longerbeam 		if (ret < 0)
222219a81c14SSteve Longerbeam 			return ret;
222319a81c14SSteve Longerbeam 		if (ret == 0)
222419a81c14SSteve Longerbeam 			return -EINVAL;
222519a81c14SSteve Longerbeam 		sensor->prev_sysclk = ret;
222619a81c14SSteve Longerbeam 	}
222719a81c14SSteve Longerbeam 
222819a81c14SSteve Longerbeam 	if (!cap_bandfilt)
222919a81c14SSteve Longerbeam 		return -EINVAL;
223019a81c14SSteve Longerbeam 
223119a81c14SSteve Longerbeam 	cap_maxband = (int)((cap_vts - 4) / cap_bandfilt);
223219a81c14SSteve Longerbeam 
223319a81c14SSteve Longerbeam 	/* calculate capture shutter/gain16 */
223419a81c14SSteve Longerbeam 	if (average > sensor->ae_low && average < sensor->ae_high) {
223519a81c14SSteve Longerbeam 		/* in stable range */
223619a81c14SSteve Longerbeam 		cap_gain16_shutter =
223719a81c14SSteve Longerbeam 			prev_gain16 * prev_shutter *
223819a81c14SSteve Longerbeam 			cap_sysclk / sensor->prev_sysclk *
223919a81c14SSteve Longerbeam 			sensor->prev_hts / cap_hts *
224019a81c14SSteve Longerbeam 			sensor->ae_target / average;
224119a81c14SSteve Longerbeam 	} else {
224219a81c14SSteve Longerbeam 		cap_gain16_shutter =
224319a81c14SSteve Longerbeam 			prev_gain16 * prev_shutter *
224419a81c14SSteve Longerbeam 			cap_sysclk / sensor->prev_sysclk *
224519a81c14SSteve Longerbeam 			sensor->prev_hts / cap_hts;
224619a81c14SSteve Longerbeam 	}
224719a81c14SSteve Longerbeam 
224819a81c14SSteve Longerbeam 	/* gain to shutter */
224919a81c14SSteve Longerbeam 	if (cap_gain16_shutter < (cap_bandfilt * 16)) {
225019a81c14SSteve Longerbeam 		/* shutter < 1/100 */
225119a81c14SSteve Longerbeam 		cap_shutter = cap_gain16_shutter / 16;
225219a81c14SSteve Longerbeam 		if (cap_shutter < 1)
225319a81c14SSteve Longerbeam 			cap_shutter = 1;
225419a81c14SSteve Longerbeam 
225519a81c14SSteve Longerbeam 		cap_gain16 = cap_gain16_shutter / cap_shutter;
225619a81c14SSteve Longerbeam 		if (cap_gain16 < 16)
225719a81c14SSteve Longerbeam 			cap_gain16 = 16;
225819a81c14SSteve Longerbeam 	} else {
225919a81c14SSteve Longerbeam 		if (cap_gain16_shutter > (cap_bandfilt * cap_maxband * 16)) {
226019a81c14SSteve Longerbeam 			/* exposure reach max */
226119a81c14SSteve Longerbeam 			cap_shutter = cap_bandfilt * cap_maxband;
226219a81c14SSteve Longerbeam 			if (!cap_shutter)
226319a81c14SSteve Longerbeam 				return -EINVAL;
226419a81c14SSteve Longerbeam 
226519a81c14SSteve Longerbeam 			cap_gain16 = cap_gain16_shutter / cap_shutter;
226619a81c14SSteve Longerbeam 		} else {
226719a81c14SSteve Longerbeam 			/* 1/100 < (cap_shutter = n/100) =< max */
226819a81c14SSteve Longerbeam 			cap_shutter =
226919a81c14SSteve Longerbeam 				((int)(cap_gain16_shutter / 16 / cap_bandfilt))
227019a81c14SSteve Longerbeam 				* cap_bandfilt;
227119a81c14SSteve Longerbeam 			if (!cap_shutter)
227219a81c14SSteve Longerbeam 				return -EINVAL;
227319a81c14SSteve Longerbeam 
227419a81c14SSteve Longerbeam 			cap_gain16 = cap_gain16_shutter / cap_shutter;
227519a81c14SSteve Longerbeam 		}
227619a81c14SSteve Longerbeam 	}
227719a81c14SSteve Longerbeam 
227819a81c14SSteve Longerbeam 	/* set capture gain */
22793cca8ef5SHugues Fruchet 	ret = ov5640_set_gain(sensor, cap_gain16);
228019a81c14SSteve Longerbeam 	if (ret)
228119a81c14SSteve Longerbeam 		return ret;
228219a81c14SSteve Longerbeam 
228319a81c14SSteve Longerbeam 	/* write capture shutter */
228419a81c14SSteve Longerbeam 	if (cap_shutter > (cap_vts - 4)) {
228519a81c14SSteve Longerbeam 		cap_vts = cap_shutter + 4;
228619a81c14SSteve Longerbeam 		ret = ov5640_set_vts(sensor, cap_vts);
228719a81c14SSteve Longerbeam 		if (ret < 0)
228819a81c14SSteve Longerbeam 			return ret;
228919a81c14SSteve Longerbeam 	}
229019a81c14SSteve Longerbeam 
229119a81c14SSteve Longerbeam 	/* set exposure */
22923cca8ef5SHugues Fruchet 	return ov5640_set_exposure(sensor, cap_shutter);
229319a81c14SSteve Longerbeam }
229419a81c14SSteve Longerbeam 
229519a81c14SSteve Longerbeam /*
229619a81c14SSteve Longerbeam  * if sensor changes inside scaling or subsampling
229719a81c14SSteve Longerbeam  * change mode directly
229819a81c14SSteve Longerbeam  */
229919a81c14SSteve Longerbeam static int ov5640_set_mode_direct(struct ov5640_dev *sensor,
23003cca8ef5SHugues Fruchet 				  const struct ov5640_mode_info *mode)
230119a81c14SSteve Longerbeam {
230241d8d7f5SHugues Fruchet 	if (!mode->reg_data)
230319a81c14SSteve Longerbeam 		return -EINVAL;
230419a81c14SSteve Longerbeam 
230519a81c14SSteve Longerbeam 	/* Write capture setting */
2306e4359019SJacopo Mondi 	ov5640_load_regs(sensor, mode->reg_data, mode->reg_data_size);
2307e4359019SJacopo Mondi 	return ov5640_set_timings(sensor, mode);
230819a81c14SSteve Longerbeam }
230919a81c14SSteve Longerbeam 
2310985cdcb0SHugues Fruchet static int ov5640_set_mode(struct ov5640_dev *sensor)
231119a81c14SSteve Longerbeam {
231219a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode = sensor->current_mode;
2313985cdcb0SHugues Fruchet 	const struct ov5640_mode_info *orig_mode = sensor->last_mode;
231419a81c14SSteve Longerbeam 	enum ov5640_downsize_mode dn_mode, orig_dn_mode;
23153cca8ef5SHugues Fruchet 	bool auto_gain = sensor->ctrls.auto_gain->val == 1;
2316dc29a1c1SHugues Fruchet 	bool auto_exp =  sensor->ctrls.auto_exp->val == V4L2_EXPOSURE_AUTO;
231719a81c14SSteve Longerbeam 	int ret;
231819a81c14SSteve Longerbeam 
231919a81c14SSteve Longerbeam 	dn_mode = mode->dn_mode;
232019a81c14SSteve Longerbeam 	orig_dn_mode = orig_mode->dn_mode;
232119a81c14SSteve Longerbeam 
232219a81c14SSteve Longerbeam 	/* auto gain and exposure must be turned off when changing modes */
23233cca8ef5SHugues Fruchet 	if (auto_gain) {
23243cca8ef5SHugues Fruchet 		ret = ov5640_set_autogain(sensor, false);
232519a81c14SSteve Longerbeam 		if (ret)
232619a81c14SSteve Longerbeam 			return ret;
23273cca8ef5SHugues Fruchet 	}
2328bf4a4b51SMaxime Ripard 
23293cca8ef5SHugues Fruchet 	if (auto_exp) {
2330dc29a1c1SHugues Fruchet 		ret = ov5640_set_autoexposure(sensor, false);
233119a81c14SSteve Longerbeam 		if (ret)
23323cca8ef5SHugues Fruchet 			goto restore_auto_gain;
23333cca8ef5SHugues Fruchet 	}
233419a81c14SSteve Longerbeam 
23356c957ed7SJacopo Mondi 	if (ov5640_is_csi2(sensor))
23366c957ed7SJacopo Mondi 		ret = ov5640_set_mipi_pclk(sensor);
23376c957ed7SJacopo Mondi 	else
23386c957ed7SJacopo Mondi 		ret = ov5640_set_dvp_pclk(sensor);
2339aa288248SMaxime Ripard 	if (ret < 0)
2340aa288248SMaxime Ripard 		return 0;
2341aa288248SMaxime Ripard 
234219a81c14SSteve Longerbeam 	if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) ||
234319a81c14SSteve Longerbeam 	    (dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) {
234419a81c14SSteve Longerbeam 		/*
234519a81c14SSteve Longerbeam 		 * change between subsampling and scaling
23463cca8ef5SHugues Fruchet 		 * go through exposure calculation
234719a81c14SSteve Longerbeam 		 */
234819a81c14SSteve Longerbeam 		ret = ov5640_set_mode_exposure_calc(sensor, mode);
234919a81c14SSteve Longerbeam 	} else {
235019a81c14SSteve Longerbeam 		/*
235119a81c14SSteve Longerbeam 		 * change inside subsampling or scaling
235219a81c14SSteve Longerbeam 		 * download firmware directly
235319a81c14SSteve Longerbeam 		 */
23543cca8ef5SHugues Fruchet 		ret = ov5640_set_mode_direct(sensor, mode);
235519a81c14SSteve Longerbeam 	}
235619a81c14SSteve Longerbeam 	if (ret < 0)
23573cca8ef5SHugues Fruchet 		goto restore_auto_exp_gain;
23583cca8ef5SHugues Fruchet 
23593cca8ef5SHugues Fruchet 	/* restore auto gain and exposure */
23603cca8ef5SHugues Fruchet 	if (auto_gain)
23613cca8ef5SHugues Fruchet 		ov5640_set_autogain(sensor, true);
23623cca8ef5SHugues Fruchet 	if (auto_exp)
23633cca8ef5SHugues Fruchet 		ov5640_set_autoexposure(sensor, true);
236419a81c14SSteve Longerbeam 
2365ce85705aSHugues Fruchet 	ret = ov5640_set_binning(sensor, dn_mode != SCALING);
2366ce85705aSHugues Fruchet 	if (ret < 0)
2367ce85705aSHugues Fruchet 		return ret;
236819a81c14SSteve Longerbeam 	ret = ov5640_set_ae_target(sensor, sensor->ae_target);
236919a81c14SSteve Longerbeam 	if (ret < 0)
237019a81c14SSteve Longerbeam 		return ret;
237119a81c14SSteve Longerbeam 	ret = ov5640_get_light_freq(sensor);
237219a81c14SSteve Longerbeam 	if (ret < 0)
237319a81c14SSteve Longerbeam 		return ret;
237419a81c14SSteve Longerbeam 	ret = ov5640_set_bandingfilter(sensor);
237519a81c14SSteve Longerbeam 	if (ret < 0)
237619a81c14SSteve Longerbeam 		return ret;
237719a81c14SSteve Longerbeam 	ret = ov5640_set_virtual_channel(sensor);
237819a81c14SSteve Longerbeam 	if (ret < 0)
237919a81c14SSteve Longerbeam 		return ret;
238019a81c14SSteve Longerbeam 
238119a81c14SSteve Longerbeam 	sensor->pending_mode_change = false;
2382985cdcb0SHugues Fruchet 	sensor->last_mode = mode;
238319a81c14SSteve Longerbeam 
238419a81c14SSteve Longerbeam 	return 0;
23853cca8ef5SHugues Fruchet 
23863cca8ef5SHugues Fruchet restore_auto_exp_gain:
23873cca8ef5SHugues Fruchet 	if (auto_exp)
23883cca8ef5SHugues Fruchet 		ov5640_set_autoexposure(sensor, true);
23893cca8ef5SHugues Fruchet restore_auto_gain:
23903cca8ef5SHugues Fruchet 	if (auto_gain)
23913cca8ef5SHugues Fruchet 		ov5640_set_autogain(sensor, true);
23923cca8ef5SHugues Fruchet 
23933cca8ef5SHugues Fruchet 	return ret;
239419a81c14SSteve Longerbeam }
239519a81c14SSteve Longerbeam 
239619ad26f9SAkinobu Mita static int ov5640_set_framefmt(struct ov5640_dev *sensor,
239719ad26f9SAkinobu Mita 			       struct v4l2_mbus_framefmt *format);
239819ad26f9SAkinobu Mita 
239919a81c14SSteve Longerbeam /* restore the last set video mode after chip power-on */
240019a81c14SSteve Longerbeam static int ov5640_restore_mode(struct ov5640_dev *sensor)
240119a81c14SSteve Longerbeam {
240219a81c14SSteve Longerbeam 	int ret;
240319a81c14SSteve Longerbeam 
240419a81c14SSteve Longerbeam 	/* first load the initial register values */
2405e4359019SJacopo Mondi 	ov5640_load_regs(sensor, ov5640_init_setting,
2406e4359019SJacopo Mondi 			 ARRAY_SIZE(ov5640_init_setting));
240719a81c14SSteve Longerbeam 
24088f57c2f8SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
24097851fe7aSMaxime Ripard 			     (ilog2(OV5640_SCLK2X_ROOT_DIV) << 2) |
24107851fe7aSMaxime Ripard 			     ilog2(OV5640_SCLK_ROOT_DIV));
24118f57c2f8SMaxime Ripard 	if (ret)
24128f57c2f8SMaxime Ripard 		return ret;
24138f57c2f8SMaxime Ripard 
241419a81c14SSteve Longerbeam 	/* now restore the last capture mode */
2415985cdcb0SHugues Fruchet 	ret = ov5640_set_mode(sensor);
241619ad26f9SAkinobu Mita 	if (ret < 0)
241719ad26f9SAkinobu Mita 		return ret;
241819ad26f9SAkinobu Mita 
241919ad26f9SAkinobu Mita 	return ov5640_set_framefmt(sensor, &sensor->fmt);
242019a81c14SSteve Longerbeam }
242119a81c14SSteve Longerbeam 
242219a81c14SSteve Longerbeam static void ov5640_power(struct ov5640_dev *sensor, bool enable)
242319a81c14SSteve Longerbeam {
24241fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->pwdn_gpio, enable ? 0 : 1);
242519a81c14SSteve Longerbeam }
242619a81c14SSteve Longerbeam 
242719a81c14SSteve Longerbeam static void ov5640_reset(struct ov5640_dev *sensor)
242819a81c14SSteve Longerbeam {
242919a81c14SSteve Longerbeam 	if (!sensor->reset_gpio)
243019a81c14SSteve Longerbeam 		return;
243119a81c14SSteve Longerbeam 
24321fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 0);
243319a81c14SSteve Longerbeam 
243419a81c14SSteve Longerbeam 	/* camera power cycle */
243519a81c14SSteve Longerbeam 	ov5640_power(sensor, false);
243619a81c14SSteve Longerbeam 	usleep_range(5000, 10000);
243719a81c14SSteve Longerbeam 	ov5640_power(sensor, true);
243819a81c14SSteve Longerbeam 	usleep_range(5000, 10000);
243919a81c14SSteve Longerbeam 
24401fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 1);
244119a81c14SSteve Longerbeam 	usleep_range(1000, 2000);
244219a81c14SSteve Longerbeam 
24431fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 0);
24441d4c41f3SLoic Poulain 	usleep_range(20000, 25000);
244519a81c14SSteve Longerbeam }
244619a81c14SSteve Longerbeam 
24470f7acb52SHugues Fruchet static int ov5640_set_power_on(struct ov5640_dev *sensor)
244819a81c14SSteve Longerbeam {
24490f7acb52SHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
24500f7acb52SHugues Fruchet 	int ret;
245119a81c14SSteve Longerbeam 
24520f7acb52SHugues Fruchet 	ret = clk_prepare_enable(sensor->xclk);
24530f7acb52SHugues Fruchet 	if (ret) {
24540f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to enable clock\n",
24550f7acb52SHugues Fruchet 			__func__);
24560f7acb52SHugues Fruchet 		return ret;
24570f7acb52SHugues Fruchet 	}
245819a81c14SSteve Longerbeam 
245919a81c14SSteve Longerbeam 	ret = regulator_bulk_enable(OV5640_NUM_SUPPLIES,
246019a81c14SSteve Longerbeam 				    sensor->supplies);
24610f7acb52SHugues Fruchet 	if (ret) {
24620f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to enable regulators\n",
24630f7acb52SHugues Fruchet 			__func__);
246419a81c14SSteve Longerbeam 		goto xclk_off;
24650f7acb52SHugues Fruchet 	}
246619a81c14SSteve Longerbeam 
246719a81c14SSteve Longerbeam 	ov5640_reset(sensor);
246819a81c14SSteve Longerbeam 	ov5640_power(sensor, true);
246919a81c14SSteve Longerbeam 
247019a81c14SSteve Longerbeam 	ret = ov5640_init_slave_id(sensor);
247119a81c14SSteve Longerbeam 	if (ret)
247219a81c14SSteve Longerbeam 		goto power_off;
247319a81c14SSteve Longerbeam 
24740f7acb52SHugues Fruchet 	return 0;
24750f7acb52SHugues Fruchet 
24760f7acb52SHugues Fruchet power_off:
24770f7acb52SHugues Fruchet 	ov5640_power(sensor, false);
24780f7acb52SHugues Fruchet 	regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies);
24790f7acb52SHugues Fruchet xclk_off:
24800f7acb52SHugues Fruchet 	clk_disable_unprepare(sensor->xclk);
24810f7acb52SHugues Fruchet 	return ret;
24820f7acb52SHugues Fruchet }
24830f7acb52SHugues Fruchet 
24840f7acb52SHugues Fruchet static void ov5640_set_power_off(struct ov5640_dev *sensor)
24850f7acb52SHugues Fruchet {
24860f7acb52SHugues Fruchet 	ov5640_power(sensor, false);
24870f7acb52SHugues Fruchet 	regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies);
24880f7acb52SHugues Fruchet 	clk_disable_unprepare(sensor->xclk);
24890f7acb52SHugues Fruchet }
24900f7acb52SHugues Fruchet 
2491b1751ae6SLad Prabhakar static int ov5640_set_power_mipi(struct ov5640_dev *sensor, bool on)
2492b1751ae6SLad Prabhakar {
2493b1751ae6SLad Prabhakar 	int ret;
2494b1751ae6SLad Prabhakar 
2495b1751ae6SLad Prabhakar 	if (!on) {
2496b1751ae6SLad Prabhakar 		/* Reset MIPI bus settings to their default values. */
2497b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
2498b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x04);
2499b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x00);
2500b1751ae6SLad Prabhakar 		return 0;
2501b1751ae6SLad Prabhakar 	}
2502b1751ae6SLad Prabhakar 
2503b1751ae6SLad Prabhakar 	/*
2504b1751ae6SLad Prabhakar 	 * Power up MIPI HS Tx and LS Rx; 2 data lanes mode
2505b1751ae6SLad Prabhakar 	 *
2506b1751ae6SLad Prabhakar 	 * 0x300e = 0x40
2507b1751ae6SLad Prabhakar 	 * [7:5] = 010	: 2 data lanes mode (see FIXME note in
2508b1751ae6SLad Prabhakar 	 *		  "ov5640_set_stream_mipi()")
2509b1751ae6SLad Prabhakar 	 * [4] = 0	: Power up MIPI HS Tx
2510b1751ae6SLad Prabhakar 	 * [3] = 0	: Power up MIPI LS Rx
2511b1751ae6SLad Prabhakar 	 * [2] = 0	: MIPI interface disabled
2512b1751ae6SLad Prabhakar 	 */
2513b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x40);
2514b1751ae6SLad Prabhakar 	if (ret)
2515b1751ae6SLad Prabhakar 		return ret;
2516b1751ae6SLad Prabhakar 
2517b1751ae6SLad Prabhakar 	/*
2518b1751ae6SLad Prabhakar 	 * Gate clock and set LP11 in 'no packets mode' (idle)
2519b1751ae6SLad Prabhakar 	 *
2520b1751ae6SLad Prabhakar 	 * 0x4800 = 0x24
2521b1751ae6SLad Prabhakar 	 * [5] = 1	: Gate clock when 'no packets'
2522b1751ae6SLad Prabhakar 	 * [2] = 1	: MIPI bus in LP11 when 'no packets'
2523b1751ae6SLad Prabhakar 	 */
2524b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x24);
2525b1751ae6SLad Prabhakar 	if (ret)
2526b1751ae6SLad Prabhakar 		return ret;
2527b1751ae6SLad Prabhakar 
2528b1751ae6SLad Prabhakar 	/*
2529b1751ae6SLad Prabhakar 	 * Set data lanes and clock in LP11 when 'sleeping'
2530b1751ae6SLad Prabhakar 	 *
2531b1751ae6SLad Prabhakar 	 * 0x3019 = 0x70
2532b1751ae6SLad Prabhakar 	 * [6] = 1	: MIPI data lane 2 in LP11 when 'sleeping'
2533b1751ae6SLad Prabhakar 	 * [5] = 1	: MIPI data lane 1 in LP11 when 'sleeping'
2534b1751ae6SLad Prabhakar 	 * [4] = 1	: MIPI clock lane in LP11 when 'sleeping'
2535b1751ae6SLad Prabhakar 	 */
2536b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x70);
2537b1751ae6SLad Prabhakar 	if (ret)
2538b1751ae6SLad Prabhakar 		return ret;
2539b1751ae6SLad Prabhakar 
2540b1751ae6SLad Prabhakar 	/* Give lanes some time to coax into LP11 state. */
2541b1751ae6SLad Prabhakar 	usleep_range(500, 1000);
2542b1751ae6SLad Prabhakar 
2543b1751ae6SLad Prabhakar 	return 0;
2544b1751ae6SLad Prabhakar }
2545b1751ae6SLad Prabhakar 
2546576f5d4bSLad Prabhakar static int ov5640_set_power_dvp(struct ov5640_dev *sensor, bool on)
2547576f5d4bSLad Prabhakar {
2548311a6408SLad Prabhakar 	unsigned int flags = sensor->ep.bus.parallel.flags;
254968579b32SHugues Fruchet 	bool bt656 = sensor->ep.bus_type == V4L2_MBUS_BT656;
255068579b32SHugues Fruchet 	u8 polarities = 0;
2551576f5d4bSLad Prabhakar 	int ret;
2552576f5d4bSLad Prabhakar 
2553576f5d4bSLad Prabhakar 	if (!on) {
2554576f5d4bSLad Prabhakar 		/* Reset settings to their default values. */
255568579b32SHugues Fruchet 		ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00, 0x00);
2556311a6408SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
2557311a6408SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, 0x20);
2558576f5d4bSLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01, 0x00);
2559576f5d4bSLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0x00);
2560576f5d4bSLad Prabhakar 		return 0;
2561576f5d4bSLad Prabhakar 	}
2562576f5d4bSLad Prabhakar 
2563576f5d4bSLad Prabhakar 	/*
2564311a6408SLad Prabhakar 	 * Note about parallel port configuration.
2565311a6408SLad Prabhakar 	 *
2566311a6408SLad Prabhakar 	 * When configured in parallel mode, the OV5640 will
2567311a6408SLad Prabhakar 	 * output 10 bits data on DVP data lines [9:0].
2568311a6408SLad Prabhakar 	 * If only 8 bits data are wanted, the 8 bits data lines
2569311a6408SLad Prabhakar 	 * of the camera interface must be physically connected
2570311a6408SLad Prabhakar 	 * on the DVP data lines [9:2].
2571311a6408SLad Prabhakar 	 *
2572311a6408SLad Prabhakar 	 * Control lines polarity can be configured through
2573311a6408SLad Prabhakar 	 * devicetree endpoint control lines properties.
2574311a6408SLad Prabhakar 	 * If no endpoint control lines properties are set,
2575311a6408SLad Prabhakar 	 * polarity will be as below:
2576311a6408SLad Prabhakar 	 * - VSYNC:	active high
2577311a6408SLad Prabhakar 	 * - HREF:	active low
2578311a6408SLad Prabhakar 	 * - PCLK:	active low
257968579b32SHugues Fruchet 	 *
258068579b32SHugues Fruchet 	 * VSYNC & HREF are not configured if BT656 bus mode is selected
2581311a6408SLad Prabhakar 	 */
258268579b32SHugues Fruchet 
258368579b32SHugues Fruchet 	/*
258468579b32SHugues Fruchet 	 * BT656 embedded synchronization configuration
258568579b32SHugues Fruchet 	 *
258668579b32SHugues Fruchet 	 * CCIR656 CTRL00
258768579b32SHugues Fruchet 	 * - [7]:	SYNC code selection (0: auto generate sync code,
258868579b32SHugues Fruchet 	 *		1: sync code from regs 0x4732-0x4735)
258968579b32SHugues Fruchet 	 * - [6]:	f value in CCIR656 SYNC code when fixed f value
259068579b32SHugues Fruchet 	 * - [5]:	Fixed f value
259168579b32SHugues Fruchet 	 * - [4:3]:	Blank toggle data options (00: data=1'h040/1'h200,
259268579b32SHugues Fruchet 	 *		01: data from regs 0x4736-0x4738, 10: always keep 0)
259368579b32SHugues Fruchet 	 * - [1]:	Clip data disable
259468579b32SHugues Fruchet 	 * - [0]:	CCIR656 mode enable
259568579b32SHugues Fruchet 	 *
259668579b32SHugues Fruchet 	 * Default CCIR656 SAV/EAV mode with default codes
259768579b32SHugues Fruchet 	 * SAV=0xff000080 & EAV=0xff00009d is enabled here with settings:
259868579b32SHugues Fruchet 	 * - CCIR656 mode enable
259968579b32SHugues Fruchet 	 * - auto generation of sync codes
260068579b32SHugues Fruchet 	 * - blank toggle data 1'h040/1'h200
260168579b32SHugues Fruchet 	 * - clip reserved data (0x00 & 0xff changed to 0x01 & 0xfe)
260268579b32SHugues Fruchet 	 */
260368579b32SHugues Fruchet 	ret = ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00,
260468579b32SHugues Fruchet 			       bt656 ? 0x01 : 0x00);
260568579b32SHugues Fruchet 	if (ret)
260668579b32SHugues Fruchet 		return ret;
260768579b32SHugues Fruchet 
2608311a6408SLad Prabhakar 	/*
2609311a6408SLad Prabhakar 	 * configure parallel port control lines polarity
2610311a6408SLad Prabhakar 	 *
2611311a6408SLad Prabhakar 	 * POLARITY CTRL0
2612311a6408SLad Prabhakar 	 * - [5]:	PCLK polarity (0: active low, 1: active high)
2613311a6408SLad Prabhakar 	 * - [1]:	HREF polarity (0: active low, 1: active high)
2614311a6408SLad Prabhakar 	 * - [0]:	VSYNC polarity (mismatch here between
2615311a6408SLad Prabhakar 	 *		datasheet and hardware, 0 is active high
2616311a6408SLad Prabhakar 	 *		and 1 is active low...)
2617311a6408SLad Prabhakar 	 */
261868579b32SHugues Fruchet 	if (!bt656) {
2619311a6408SLad Prabhakar 		if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
262068579b32SHugues Fruchet 			polarities |= BIT(1);
2621311a6408SLad Prabhakar 		if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
262268579b32SHugues Fruchet 			polarities |= BIT(0);
262368579b32SHugues Fruchet 	}
262468579b32SHugues Fruchet 	if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
262568579b32SHugues Fruchet 		polarities |= BIT(5);
2626311a6408SLad Prabhakar 
262768579b32SHugues Fruchet 	ret = ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, polarities);
2628311a6408SLad Prabhakar 	if (ret)
2629311a6408SLad Prabhakar 		return ret;
2630311a6408SLad Prabhakar 
2631311a6408SLad Prabhakar 	/*
263268579b32SHugues Fruchet 	 * powerdown MIPI TX/RX PHY & enable DVP
2633311a6408SLad Prabhakar 	 *
2634311a6408SLad Prabhakar 	 * MIPI CONTROL 00
263568579b32SHugues Fruchet 	 * [4] = 1	: Power down MIPI HS Tx
263668579b32SHugues Fruchet 	 * [3] = 1	: Power down MIPI LS Rx
263768579b32SHugues Fruchet 	 * [2] = 0	: DVP enable (MIPI disable)
2638311a6408SLad Prabhakar 	 */
2639311a6408SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x18);
2640311a6408SLad Prabhakar 	if (ret)
2641311a6408SLad Prabhakar 		return ret;
2642311a6408SLad Prabhakar 
2643311a6408SLad Prabhakar 	/*
2644576f5d4bSLad Prabhakar 	 * enable VSYNC/HREF/PCLK DVP control lines
2645576f5d4bSLad Prabhakar 	 * & D[9:6] DVP data lines
2646576f5d4bSLad Prabhakar 	 *
2647576f5d4bSLad Prabhakar 	 * PAD OUTPUT ENABLE 01
2648576f5d4bSLad Prabhakar 	 * - 6:		VSYNC output enable
2649576f5d4bSLad Prabhakar 	 * - 5:		HREF output enable
2650576f5d4bSLad Prabhakar 	 * - 4:		PCLK output enable
2651576f5d4bSLad Prabhakar 	 * - [3:0]:	D[9:6] output enable
2652576f5d4bSLad Prabhakar 	 */
26534039b037SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01,
265468579b32SHugues Fruchet 			       bt656 ? 0x1f : 0x7f);
2655576f5d4bSLad Prabhakar 	if (ret)
2656576f5d4bSLad Prabhakar 		return ret;
2657576f5d4bSLad Prabhakar 
2658576f5d4bSLad Prabhakar 	/*
2659576f5d4bSLad Prabhakar 	 * enable D[5:0] DVP data lines
2660576f5d4bSLad Prabhakar 	 *
2661576f5d4bSLad Prabhakar 	 * PAD OUTPUT ENABLE 02
2662576f5d4bSLad Prabhakar 	 * - [7:2]:	D[5:0] output enable
2663576f5d4bSLad Prabhakar 	 */
2664576f5d4bSLad Prabhakar 	return ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0xfc);
2665576f5d4bSLad Prabhakar }
2666576f5d4bSLad Prabhakar 
26670f7acb52SHugues Fruchet static int ov5640_set_power(struct ov5640_dev *sensor, bool on)
26680f7acb52SHugues Fruchet {
26690f7acb52SHugues Fruchet 	int ret = 0;
26700f7acb52SHugues Fruchet 
26710f7acb52SHugues Fruchet 	if (on) {
26720f7acb52SHugues Fruchet 		ret = ov5640_set_power_on(sensor);
26730f7acb52SHugues Fruchet 		if (ret)
26740f7acb52SHugues Fruchet 			return ret;
26750f7acb52SHugues Fruchet 
267619a81c14SSteve Longerbeam 		ret = ov5640_restore_mode(sensor);
267719a81c14SSteve Longerbeam 		if (ret)
267819a81c14SSteve Longerbeam 			goto power_off;
2679b1751ae6SLad Prabhakar 	}
268019a81c14SSteve Longerbeam 
2681576f5d4bSLad Prabhakar 	if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY)
2682b1751ae6SLad Prabhakar 		ret = ov5640_set_power_mipi(sensor, on);
2683576f5d4bSLad Prabhakar 	else
2684576f5d4bSLad Prabhakar 		ret = ov5640_set_power_dvp(sensor, on);
2685b1751ae6SLad Prabhakar 	if (ret)
2686b1751ae6SLad Prabhakar 		goto power_off;
2687aa4bb8b8SJacopo Mondi 
2688b1751ae6SLad Prabhakar 	if (!on)
2689aa4bb8b8SJacopo Mondi 		ov5640_set_power_off(sensor);
269019a81c14SSteve Longerbeam 
269119a81c14SSteve Longerbeam 	return 0;
269219a81c14SSteve Longerbeam 
269319a81c14SSteve Longerbeam power_off:
26940f7acb52SHugues Fruchet 	ov5640_set_power_off(sensor);
269519a81c14SSteve Longerbeam 	return ret;
269619a81c14SSteve Longerbeam }
269719a81c14SSteve Longerbeam 
269885644a9bSPaul Elder static int ov5640_sensor_suspend(struct device *dev)
269919a81c14SSteve Longerbeam {
270085644a9bSPaul Elder 	struct v4l2_subdev *sd = dev_get_drvdata(dev);
270185644a9bSPaul Elder 	struct ov5640_dev *ov5640 = to_ov5640_dev(sd);
270219a81c14SSteve Longerbeam 
270385644a9bSPaul Elder 	return ov5640_set_power(ov5640, false);
270419a81c14SSteve Longerbeam }
270519a81c14SSteve Longerbeam 
270685644a9bSPaul Elder static int ov5640_sensor_resume(struct device *dev)
270785644a9bSPaul Elder {
270885644a9bSPaul Elder 	struct v4l2_subdev *sd = dev_get_drvdata(dev);
270985644a9bSPaul Elder 	struct ov5640_dev *ov5640 = to_ov5640_dev(sd);
271019a81c14SSteve Longerbeam 
271185644a9bSPaul Elder 	return ov5640_set_power(ov5640, true);
271219a81c14SSteve Longerbeam }
271319a81c14SSteve Longerbeam 
271485644a9bSPaul Elder /* --------------- Subdev Operations --------------- */
271519a81c14SSteve Longerbeam 
271619a81c14SSteve Longerbeam static int ov5640_try_frame_interval(struct ov5640_dev *sensor,
271719a81c14SSteve Longerbeam 				     struct v4l2_fract *fi,
2718*f33b56d3SGuoniu.zhou 				     const struct ov5640_mode_info *mode_info)
271919a81c14SSteve Longerbeam {
2720*f33b56d3SGuoniu.zhou 	const struct ov5640_mode_info *mode = mode_info;
27216530a5ebSJagan Teki 	enum ov5640_frame_rate rate = OV5640_15_FPS;
2722f6cc192fSMaxime Ripard 	int minfps, maxfps, best_fps, fps;
2723f6cc192fSMaxime Ripard 	int i;
272419a81c14SSteve Longerbeam 
272519a81c14SSteve Longerbeam 	minfps = ov5640_framerates[OV5640_15_FPS];
2726*f33b56d3SGuoniu.zhou 	maxfps = ov5640_framerates[mode->max_fps];
272719a81c14SSteve Longerbeam 
272819a81c14SSteve Longerbeam 	if (fi->numerator == 0) {
272919a81c14SSteve Longerbeam 		fi->denominator = maxfps;
273019a81c14SSteve Longerbeam 		fi->numerator = 1;
2731*f33b56d3SGuoniu.zhou 		rate = mode->max_fps;
2732e823fb16SMaxime Ripard 		goto find_mode;
273319a81c14SSteve Longerbeam 	}
273419a81c14SSteve Longerbeam 
2735f6cc192fSMaxime Ripard 	fps = clamp_val(DIV_ROUND_CLOSEST(fi->denominator, fi->numerator),
2736f6cc192fSMaxime Ripard 			minfps, maxfps);
2737f6cc192fSMaxime Ripard 
2738f6cc192fSMaxime Ripard 	best_fps = minfps;
2739f6cc192fSMaxime Ripard 	for (i = 0; i < ARRAY_SIZE(ov5640_framerates); i++) {
2740f6cc192fSMaxime Ripard 		int curr_fps = ov5640_framerates[i];
2741f6cc192fSMaxime Ripard 
2742f6cc192fSMaxime Ripard 		if (abs(curr_fps - fps) < abs(best_fps - fps)) {
2743f6cc192fSMaxime Ripard 			best_fps = curr_fps;
2744f6cc192fSMaxime Ripard 			rate = i;
2745f6cc192fSMaxime Ripard 		}
2746f6cc192fSMaxime Ripard 	}
274719a81c14SSteve Longerbeam 
274819a81c14SSteve Longerbeam 	fi->numerator = 1;
2749f6cc192fSMaxime Ripard 	fi->denominator = best_fps;
275019a81c14SSteve Longerbeam 
2751e823fb16SMaxime Ripard find_mode:
2752*f33b56d3SGuoniu.zhou 	mode = ov5640_find_mode(sensor, mode->width, mode->height, false);
27535a3ad937SMaxime Ripard 	return mode ? rate : -EINVAL;
275419a81c14SSteve Longerbeam }
275519a81c14SSteve Longerbeam 
275619a81c14SSteve Longerbeam static int ov5640_get_fmt(struct v4l2_subdev *sd,
27570d346d2aSTomi Valkeinen 			  struct v4l2_subdev_state *sd_state,
275819a81c14SSteve Longerbeam 			  struct v4l2_subdev_format *format)
275919a81c14SSteve Longerbeam {
276019a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
276119a81c14SSteve Longerbeam 	struct v4l2_mbus_framefmt *fmt;
276219a81c14SSteve Longerbeam 
276319a81c14SSteve Longerbeam 	if (format->pad != 0)
276419a81c14SSteve Longerbeam 		return -EINVAL;
276519a81c14SSteve Longerbeam 
276619a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
276719a81c14SSteve Longerbeam 
276819a81c14SSteve Longerbeam 	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
27690d346d2aSTomi Valkeinen 		fmt = v4l2_subdev_get_try_format(&sensor->sd, sd_state,
277019a81c14SSteve Longerbeam 						 format->pad);
277119a81c14SSteve Longerbeam 	else
277219a81c14SSteve Longerbeam 		fmt = &sensor->fmt;
277319a81c14SSteve Longerbeam 
277419a81c14SSteve Longerbeam 	format->format = *fmt;
277519a81c14SSteve Longerbeam 
277619a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
277719a81c14SSteve Longerbeam 
277819a81c14SSteve Longerbeam 	return 0;
277919a81c14SSteve Longerbeam }
278019a81c14SSteve Longerbeam 
278119a81c14SSteve Longerbeam static int ov5640_try_fmt_internal(struct v4l2_subdev *sd,
278219a81c14SSteve Longerbeam 				   struct v4l2_mbus_framefmt *fmt,
278319a81c14SSteve Longerbeam 				   enum ov5640_frame_rate fr,
278419a81c14SSteve Longerbeam 				   const struct ov5640_mode_info **new_mode)
278519a81c14SSteve Longerbeam {
278619a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
278719a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
2788a89f14bbSJacopo Mondi 	const struct ov5640_pixfmt *pixfmt;
2789a89f14bbSJacopo Mondi 	unsigned int bpp;
279019a81c14SSteve Longerbeam 
2791b6ae5022SJacopo Mondi 	mode = ov5640_find_mode(sensor, fmt->width, fmt->height, true);
279219a81c14SSteve Longerbeam 	if (!mode)
279319a81c14SSteve Longerbeam 		return -EINVAL;
2794dd81b8ffSJacopo Mondi 
2795a89f14bbSJacopo Mondi 	pixfmt = ov5640_code_to_pixfmt(sensor, fmt->code);
2796a89f14bbSJacopo Mondi 	bpp = pixfmt->bpp;
2797a89f14bbSJacopo Mondi 
2798dd81b8ffSJacopo Mondi 	/*
2799dd81b8ffSJacopo Mondi 	 * Adjust mode according to bpp:
2800dd81b8ffSJacopo Mondi 	 * - 8bpp modes work for resolution >= 1280x720
2801dd81b8ffSJacopo Mondi 	 * - 24bpp modes work resolution < 1280x720
2802dd81b8ffSJacopo Mondi 	 */
2803dd81b8ffSJacopo Mondi 	if (bpp == 8 && mode->width < 1280)
2804dd81b8ffSJacopo Mondi 		mode = &ov5640_mode_data[OV5640_MODE_720P_1280_720];
2805dd81b8ffSJacopo Mondi 	else if (bpp == 24 && mode->width > 1024)
2806dd81b8ffSJacopo Mondi 		mode = &ov5640_mode_data[OV5640_MODE_XGA_1024_768];
2807dd81b8ffSJacopo Mondi 
28085113d5b3SJacopo Mondi 	fmt->width = mode->width;
28095113d5b3SJacopo Mondi 	fmt->height = mode->height;
281019a81c14SSteve Longerbeam 
281119a81c14SSteve Longerbeam 	if (new_mode)
281219a81c14SSteve Longerbeam 		*new_mode = mode;
2813e3ee691dSHugues Fruchet 
2814a89f14bbSJacopo Mondi 	fmt->code = pixfmt->code;
2815a89f14bbSJacopo Mondi 	fmt->colorspace = pixfmt->colorspace;
2816e6441fdeSHugues Fruchet 	fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
2817e6441fdeSHugues Fruchet 	fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
2818e6441fdeSHugues Fruchet 	fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
2819e3ee691dSHugues Fruchet 
282019a81c14SSteve Longerbeam 	return 0;
282119a81c14SSteve Longerbeam }
282219a81c14SSteve Longerbeam 
28233c28588fSJacopo Mondi static int ov5640_update_pixel_rate(struct ov5640_dev *sensor)
28243c28588fSJacopo Mondi {
28253c28588fSJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
28263c28588fSJacopo Mondi 	enum ov5640_pixel_rate_id pixel_rate_id = mode->pixel_rate;
28273c28588fSJacopo Mondi 	struct v4l2_mbus_framefmt *fmt = &sensor->fmt;
282832979f67SJacopo Mondi 	const struct ov5640_timings *timings;
2829bce93b82SJacopo Mondi 	s32 exposure_val, exposure_max;
283032979f67SJacopo Mondi 	unsigned int hblank;
28313c28588fSJacopo Mondi 	unsigned int i = 0;
28323c28588fSJacopo Mondi 	u32 pixel_rate;
28333c28588fSJacopo Mondi 	s64 link_freq;
28343c28588fSJacopo Mondi 	u32 num_lanes;
283519f2e3e6SHugues Fruchet 	u32 vblank;
28363c28588fSJacopo Mondi 	u32 bpp;
28373c28588fSJacopo Mondi 
28383c28588fSJacopo Mondi 	/*
28393c28588fSJacopo Mondi 	 * Update the pixel rate control value.
28403c28588fSJacopo Mondi 	 *
28413c28588fSJacopo Mondi 	 * For DVP mode, maintain the pixel rate calculation using fixed FPS.
28423c28588fSJacopo Mondi 	 */
28433c28588fSJacopo Mondi 	if (!ov5640_is_csi2(sensor)) {
28443c28588fSJacopo Mondi 		__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate,
28453c28588fSJacopo Mondi 					 ov5640_calc_pixel_rate(sensor));
28463c28588fSJacopo Mondi 
28473c28588fSJacopo Mondi 		return 0;
28483c28588fSJacopo Mondi 	}
28493c28588fSJacopo Mondi 
28503c28588fSJacopo Mondi 	/*
28513c28588fSJacopo Mondi 	 * The MIPI CSI-2 link frequency should comply with the CSI-2
28523c28588fSJacopo Mondi 	 * specification and be lower than 1GHz.
28533c28588fSJacopo Mondi 	 *
28543c28588fSJacopo Mondi 	 * Start from the suggested pixel_rate for the current mode and
28553c28588fSJacopo Mondi 	 * progressively slow it down if it exceeds 1GHz.
28563c28588fSJacopo Mondi 	 */
28573c28588fSJacopo Mondi 	num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes;
2858a89f14bbSJacopo Mondi 	bpp = ov5640_code_to_bpp(sensor, fmt->code);
28593c28588fSJacopo Mondi 	do {
28603c28588fSJacopo Mondi 		pixel_rate = ov5640_pixel_rates[pixel_rate_id];
28613c28588fSJacopo Mondi 		link_freq = pixel_rate * bpp / (2 * num_lanes);
28623c28588fSJacopo Mondi 	} while (link_freq >= 1000000000U &&
28633c28588fSJacopo Mondi 		 ++pixel_rate_id < OV5640_NUM_PIXEL_RATES);
28643c28588fSJacopo Mondi 
28653c28588fSJacopo Mondi 	sensor->current_link_freq = link_freq;
28663c28588fSJacopo Mondi 
28673c28588fSJacopo Mondi 	/*
28683c28588fSJacopo Mondi 	 * Higher link rates require the clock tree to be programmed with
28693c28588fSJacopo Mondi 	 * 'mipi_div' = 1; this has the effect of halving the actual output
28703c28588fSJacopo Mondi 	 * pixel rate in the MIPI domain.
28713c28588fSJacopo Mondi 	 *
28723c28588fSJacopo Mondi 	 * Adjust the pixel rate and link frequency control value to report it
28733c28588fSJacopo Mondi 	 * correctly to userspace.
28743c28588fSJacopo Mondi 	 */
28753c28588fSJacopo Mondi 	if (link_freq > OV5640_LINK_RATE_MAX) {
28763c28588fSJacopo Mondi 		pixel_rate /= 2;
28773c28588fSJacopo Mondi 		link_freq /= 2;
28783c28588fSJacopo Mondi 	}
28793c28588fSJacopo Mondi 
28803c28588fSJacopo Mondi 	for (i = 0; i < ARRAY_SIZE(ov5640_csi2_link_freqs); ++i) {
28813c28588fSJacopo Mondi 		if (ov5640_csi2_link_freqs[i] == link_freq)
28823c28588fSJacopo Mondi 			break;
28833c28588fSJacopo Mondi 	}
28843c28588fSJacopo Mondi 	WARN_ON(i == ARRAY_SIZE(ov5640_csi2_link_freqs));
28853c28588fSJacopo Mondi 
28863c28588fSJacopo Mondi 	__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, pixel_rate);
28873c28588fSJacopo Mondi 	__v4l2_ctrl_s_ctrl(sensor->ctrls.link_freq, i);
28883c28588fSJacopo Mondi 
288932979f67SJacopo Mondi 	timings = ov5640_timings(sensor, mode);
289032979f67SJacopo Mondi 	hblank = timings->htot - mode->width;
289132979f67SJacopo Mondi 	__v4l2_ctrl_modify_range(sensor->ctrls.hblank,
289232979f67SJacopo Mondi 				 hblank, hblank, 1, hblank);
289332979f67SJacopo Mondi 
289419f2e3e6SHugues Fruchet 	vblank = timings->vblank_def;
2895bce93b82SJacopo Mondi 
289619f2e3e6SHugues Fruchet 	if (sensor->current_fr != mode->def_fps) {
289719f2e3e6SHugues Fruchet 		/*
289819f2e3e6SHugues Fruchet 		 * Compute the vertical blanking according to the framerate
289919f2e3e6SHugues Fruchet 		 * configured with s_frame_interval.
290019f2e3e6SHugues Fruchet 		 */
290119f2e3e6SHugues Fruchet 		int fie_num = sensor->frame_interval.numerator;
290219f2e3e6SHugues Fruchet 		int fie_denom = sensor->frame_interval.denominator;
290319f2e3e6SHugues Fruchet 
290419f2e3e6SHugues Fruchet 		vblank = ((fie_num * pixel_rate / fie_denom) / timings->htot) -
290519f2e3e6SHugues Fruchet 			mode->height;
290619f2e3e6SHugues Fruchet 	}
290719f2e3e6SHugues Fruchet 
290819f2e3e6SHugues Fruchet 	__v4l2_ctrl_modify_range(sensor->ctrls.vblank, OV5640_MIN_VBLANK,
290919f2e3e6SHugues Fruchet 				 OV5640_MAX_VTS - mode->height, 1, vblank);
291019f2e3e6SHugues Fruchet 	__v4l2_ctrl_s_ctrl(sensor->ctrls.vblank, vblank);
291119f2e3e6SHugues Fruchet 
291219f2e3e6SHugues Fruchet 	exposure_max = timings->crop.height + vblank - 4;
2913bce93b82SJacopo Mondi 	exposure_val = clamp_t(s32, sensor->ctrls.exposure->val,
2914bce93b82SJacopo Mondi 			       sensor->ctrls.exposure->minimum,
2915bce93b82SJacopo Mondi 			       exposure_max);
291619f2e3e6SHugues Fruchet 
2917bce93b82SJacopo Mondi 	__v4l2_ctrl_modify_range(sensor->ctrls.exposure,
2918bce93b82SJacopo Mondi 				 sensor->ctrls.exposure->minimum,
2919bce93b82SJacopo Mondi 				 exposure_max, 1, exposure_val);
2920bce93b82SJacopo Mondi 
29213c28588fSJacopo Mondi 	return 0;
29223c28588fSJacopo Mondi }
29233c28588fSJacopo Mondi 
292419a81c14SSteve Longerbeam static int ov5640_set_fmt(struct v4l2_subdev *sd,
29250d346d2aSTomi Valkeinen 			  struct v4l2_subdev_state *sd_state,
292619a81c14SSteve Longerbeam 			  struct v4l2_subdev_format *format)
292719a81c14SSteve Longerbeam {
292819a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
292919a81c14SSteve Longerbeam 	const struct ov5640_mode_info *new_mode;
2930e6441fdeSHugues Fruchet 	struct v4l2_mbus_framefmt *mbus_fmt = &format->format;
293119a81c14SSteve Longerbeam 	int ret;
293219a81c14SSteve Longerbeam 
293319a81c14SSteve Longerbeam 	if (format->pad != 0)
293419a81c14SSteve Longerbeam 		return -EINVAL;
293519a81c14SSteve Longerbeam 
293619a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
293719a81c14SSteve Longerbeam 
293819a81c14SSteve Longerbeam 	if (sensor->streaming) {
293919a81c14SSteve Longerbeam 		ret = -EBUSY;
294019a81c14SSteve Longerbeam 		goto out;
294119a81c14SSteve Longerbeam 	}
294219a81c14SSteve Longerbeam 
2943e6441fdeSHugues Fruchet 	ret = ov5640_try_fmt_internal(sd, mbus_fmt,
294419a81c14SSteve Longerbeam 				      sensor->current_fr, &new_mode);
294519a81c14SSteve Longerbeam 	if (ret)
294619a81c14SSteve Longerbeam 		goto out;
294719a81c14SSteve Longerbeam 
2948e738f5ddSMirela Rabulea 	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
2949e738f5ddSMirela Rabulea 		*v4l2_subdev_get_try_format(sd, sd_state, 0) = *mbus_fmt;
2950e738f5ddSMirela Rabulea 		goto out;
2951e738f5ddSMirela Rabulea 	}
295219a81c14SSteve Longerbeam 
29536949d864SHugues Fruchet 	if (new_mode != sensor->current_mode) {
295419f2e3e6SHugues Fruchet 		sensor->current_fr = new_mode->def_fps;
295519a81c14SSteve Longerbeam 		sensor->current_mode = new_mode;
295619a81c14SSteve Longerbeam 		sensor->pending_mode_change = true;
29576949d864SHugues Fruchet 	}
295807115449SJacopo Mondi 	if (mbus_fmt->code != sensor->fmt.code)
2959fb98e29fSHugues Fruchet 		sensor->pending_fmt_change = true;
296007115449SJacopo Mondi 
2961e738f5ddSMirela Rabulea 	/* update format even if code is unchanged, resolution might change */
2962e738f5ddSMirela Rabulea 	sensor->fmt = *mbus_fmt;
2963e738f5ddSMirela Rabulea 
29643c28588fSJacopo Mondi 	ov5640_update_pixel_rate(sensor);
29653c28588fSJacopo Mondi 
296619a81c14SSteve Longerbeam out:
296719a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
296819a81c14SSteve Longerbeam 	return ret;
296919a81c14SSteve Longerbeam }
297019a81c14SSteve Longerbeam 
297166ed85ebSJacopo Mondi static int ov5640_get_selection(struct v4l2_subdev *sd,
297266ed85ebSJacopo Mondi 				struct v4l2_subdev_state *sd_state,
297366ed85ebSJacopo Mondi 				struct v4l2_subdev_selection *sel)
297466ed85ebSJacopo Mondi {
297566ed85ebSJacopo Mondi 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
297666ed85ebSJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
297766ed85ebSJacopo Mondi 	const struct ov5640_timings *timings;
297866ed85ebSJacopo Mondi 
297966ed85ebSJacopo Mondi 	switch (sel->target) {
298066ed85ebSJacopo Mondi 	case V4L2_SEL_TGT_CROP: {
298166ed85ebSJacopo Mondi 		mutex_lock(&sensor->lock);
298266ed85ebSJacopo Mondi 		timings = ov5640_timings(sensor, mode);
298366ed85ebSJacopo Mondi 		sel->r = timings->analog_crop;
298466ed85ebSJacopo Mondi 		mutex_unlock(&sensor->lock);
298566ed85ebSJacopo Mondi 
298666ed85ebSJacopo Mondi 		return 0;
298766ed85ebSJacopo Mondi 	}
298866ed85ebSJacopo Mondi 
298966ed85ebSJacopo Mondi 	case V4L2_SEL_TGT_NATIVE_SIZE:
299066ed85ebSJacopo Mondi 	case V4L2_SEL_TGT_CROP_BOUNDS:
299166ed85ebSJacopo Mondi 		sel->r.top = 0;
299266ed85ebSJacopo Mondi 		sel->r.left = 0;
299366ed85ebSJacopo Mondi 		sel->r.width = OV5640_NATIVE_WIDTH;
299466ed85ebSJacopo Mondi 		sel->r.height = OV5640_NATIVE_HEIGHT;
299566ed85ebSJacopo Mondi 
299666ed85ebSJacopo Mondi 		return 0;
299766ed85ebSJacopo Mondi 
299866ed85ebSJacopo Mondi 	case V4L2_SEL_TGT_CROP_DEFAULT:
299966ed85ebSJacopo Mondi 		sel->r.top = OV5640_PIXEL_ARRAY_TOP;
300066ed85ebSJacopo Mondi 		sel->r.left = OV5640_PIXEL_ARRAY_LEFT;
300166ed85ebSJacopo Mondi 		sel->r.width = OV5640_PIXEL_ARRAY_WIDTH;
300266ed85ebSJacopo Mondi 		sel->r.height = OV5640_PIXEL_ARRAY_HEIGHT;
300366ed85ebSJacopo Mondi 
300466ed85ebSJacopo Mondi 		return 0;
300566ed85ebSJacopo Mondi 	}
300666ed85ebSJacopo Mondi 
300766ed85ebSJacopo Mondi 	return -EINVAL;
300866ed85ebSJacopo Mondi }
300966ed85ebSJacopo Mondi 
3010e3ee691dSHugues Fruchet static int ov5640_set_framefmt(struct ov5640_dev *sensor,
3011e3ee691dSHugues Fruchet 			       struct v4l2_mbus_framefmt *format)
3012e3ee691dSHugues Fruchet {
3013935fbc94SJacopo Mondi 	bool is_jpeg = format->code == MEDIA_BUS_FMT_JPEG_1X8;
3014935fbc94SJacopo Mondi 	const struct ov5640_pixfmt *pixfmt;
3015e3ee691dSHugues Fruchet 	int ret = 0;
3016e3ee691dSHugues Fruchet 
3017935fbc94SJacopo Mondi 	pixfmt = ov5640_code_to_pixfmt(sensor, format->code);
3018e3ee691dSHugues Fruchet 
3019e3ee691dSHugues Fruchet 	/* FORMAT CONTROL00: YUV and RGB formatting */
3020935fbc94SJacopo Mondi 	ret = ov5640_write_reg(sensor, OV5640_REG_FORMAT_CONTROL00,
3021935fbc94SJacopo Mondi 			       pixfmt->ctrl00);
3022e3ee691dSHugues Fruchet 	if (ret)
3023e3ee691dSHugues Fruchet 		return ret;
3024e3ee691dSHugues Fruchet 
3025e3ee691dSHugues Fruchet 	/* FORMAT MUX CONTROL: ISP YUV or RGB */
3026935fbc94SJacopo Mondi 	ret = ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL,
3027935fbc94SJacopo Mondi 			       pixfmt->mux);
3028d47c4126SHugues Fruchet 	if (ret)
3029d47c4126SHugues Fruchet 		return ret;
3030d47c4126SHugues Fruchet 
3031d47c4126SHugues Fruchet 	/*
3032d47c4126SHugues Fruchet 	 * TIMING TC REG21:
3033d47c4126SHugues Fruchet 	 * - [5]:	JPEG enable
3034d47c4126SHugues Fruchet 	 */
3035d47c4126SHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
3036d47c4126SHugues Fruchet 			     BIT(5), is_jpeg ? BIT(5) : 0);
3037d47c4126SHugues Fruchet 	if (ret)
3038d47c4126SHugues Fruchet 		return ret;
3039d47c4126SHugues Fruchet 
3040d47c4126SHugues Fruchet 	/*
3041d47c4126SHugues Fruchet 	 * SYSTEM RESET02:
3042d47c4126SHugues Fruchet 	 * - [4]:	Reset JFIFO
3043d47c4126SHugues Fruchet 	 * - [3]:	Reset SFIFO
3044d47c4126SHugues Fruchet 	 * - [2]:	Reset JPEG
3045d47c4126SHugues Fruchet 	 */
3046d47c4126SHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_RESET02,
3047d47c4126SHugues Fruchet 			     BIT(4) | BIT(3) | BIT(2),
3048d47c4126SHugues Fruchet 			     is_jpeg ? 0 : (BIT(4) | BIT(3) | BIT(2)));
3049d47c4126SHugues Fruchet 	if (ret)
3050d47c4126SHugues Fruchet 		return ret;
3051d47c4126SHugues Fruchet 
3052d47c4126SHugues Fruchet 	/*
3053d47c4126SHugues Fruchet 	 * CLOCK ENABLE02:
3054d47c4126SHugues Fruchet 	 * - [5]:	Enable JPEG 2x clock
3055d47c4126SHugues Fruchet 	 * - [3]:	Enable JPEG clock
3056d47c4126SHugues Fruchet 	 */
3057d47c4126SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_SYS_CLOCK_ENABLE02,
3058d47c4126SHugues Fruchet 			      BIT(5) | BIT(3),
3059d47c4126SHugues Fruchet 			      is_jpeg ? (BIT(5) | BIT(3)) : 0);
3060e3ee691dSHugues Fruchet }
306119a81c14SSteve Longerbeam 
306219a81c14SSteve Longerbeam /*
306319a81c14SSteve Longerbeam  * Sensor Controls.
306419a81c14SSteve Longerbeam  */
306519a81c14SSteve Longerbeam 
306619a81c14SSteve Longerbeam static int ov5640_set_ctrl_hue(struct ov5640_dev *sensor, int value)
306719a81c14SSteve Longerbeam {
306819a81c14SSteve Longerbeam 	int ret;
306919a81c14SSteve Longerbeam 
307019a81c14SSteve Longerbeam 	if (value) {
307119a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
307219a81c14SSteve Longerbeam 				     BIT(0), BIT(0));
307319a81c14SSteve Longerbeam 		if (ret)
307419a81c14SSteve Longerbeam 			return ret;
307519a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_SDE_CTRL1, value);
307619a81c14SSteve Longerbeam 	} else {
307719a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(0), 0);
307819a81c14SSteve Longerbeam 	}
307919a81c14SSteve Longerbeam 
308019a81c14SSteve Longerbeam 	return ret;
308119a81c14SSteve Longerbeam }
308219a81c14SSteve Longerbeam 
308319a81c14SSteve Longerbeam static int ov5640_set_ctrl_contrast(struct ov5640_dev *sensor, int value)
308419a81c14SSteve Longerbeam {
308519a81c14SSteve Longerbeam 	int ret;
308619a81c14SSteve Longerbeam 
308719a81c14SSteve Longerbeam 	if (value) {
308819a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
308919a81c14SSteve Longerbeam 				     BIT(2), BIT(2));
309019a81c14SSteve Longerbeam 		if (ret)
309119a81c14SSteve Longerbeam 			return ret;
309219a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL5,
309319a81c14SSteve Longerbeam 				       value & 0xff);
309419a81c14SSteve Longerbeam 	} else {
309519a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(2), 0);
309619a81c14SSteve Longerbeam 	}
309719a81c14SSteve Longerbeam 
309819a81c14SSteve Longerbeam 	return ret;
309919a81c14SSteve Longerbeam }
310019a81c14SSteve Longerbeam 
310119a81c14SSteve Longerbeam static int ov5640_set_ctrl_saturation(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(1), BIT(1));
310819a81c14SSteve Longerbeam 		if (ret)
310919a81c14SSteve Longerbeam 			return ret;
311019a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL3,
311119a81c14SSteve Longerbeam 				       value & 0xff);
311219a81c14SSteve Longerbeam 		if (ret)
311319a81c14SSteve Longerbeam 			return ret;
311419a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL4,
311519a81c14SSteve Longerbeam 				       value & 0xff);
311619a81c14SSteve Longerbeam 	} else {
311719a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(1), 0);
311819a81c14SSteve Longerbeam 	}
311919a81c14SSteve Longerbeam 
312019a81c14SSteve Longerbeam 	return ret;
312119a81c14SSteve Longerbeam }
312219a81c14SSteve Longerbeam 
312319a81c14SSteve Longerbeam static int ov5640_set_ctrl_white_balance(struct ov5640_dev *sensor, int awb)
312419a81c14SSteve Longerbeam {
312519a81c14SSteve Longerbeam 	int ret;
312619a81c14SSteve Longerbeam 
312719a81c14SSteve Longerbeam 	ret = ov5640_mod_reg(sensor, OV5640_REG_AWB_MANUAL_CTRL,
312819a81c14SSteve Longerbeam 			     BIT(0), awb ? 0 : 1);
312919a81c14SSteve Longerbeam 	if (ret)
313019a81c14SSteve Longerbeam 		return ret;
313119a81c14SSteve Longerbeam 
313219a81c14SSteve Longerbeam 	if (!awb) {
313319a81c14SSteve Longerbeam 		u16 red = (u16)sensor->ctrls.red_balance->val;
313419a81c14SSteve Longerbeam 		u16 blue = (u16)sensor->ctrls.blue_balance->val;
313519a81c14SSteve Longerbeam 
313619a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_R_GAIN, red);
313719a81c14SSteve Longerbeam 		if (ret)
313819a81c14SSteve Longerbeam 			return ret;
313919a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_B_GAIN, blue);
314019a81c14SSteve Longerbeam 	}
314119a81c14SSteve Longerbeam 
314219a81c14SSteve Longerbeam 	return ret;
314319a81c14SSteve Longerbeam }
314419a81c14SSteve Longerbeam 
31453cca8ef5SHugues Fruchet static int ov5640_set_ctrl_exposure(struct ov5640_dev *sensor,
31463cca8ef5SHugues Fruchet 				    enum v4l2_exposure_auto_type auto_exposure)
314719a81c14SSteve Longerbeam {
314819a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
31493cca8ef5SHugues Fruchet 	bool auto_exp = (auto_exposure == V4L2_EXPOSURE_AUTO);
315019a81c14SSteve Longerbeam 	int ret = 0;
315119a81c14SSteve Longerbeam 
315219a81c14SSteve Longerbeam 	if (ctrls->auto_exp->is_new) {
31533cca8ef5SHugues Fruchet 		ret = ov5640_set_autoexposure(sensor, auto_exp);
315419a81c14SSteve Longerbeam 		if (ret)
315519a81c14SSteve Longerbeam 			return ret;
315619a81c14SSteve Longerbeam 	}
315719a81c14SSteve Longerbeam 
31583cca8ef5SHugues Fruchet 	if (!auto_exp && ctrls->exposure->is_new) {
315919a81c14SSteve Longerbeam 		u16 max_exp;
316019a81c14SSteve Longerbeam 
316119a81c14SSteve Longerbeam 		ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_VTS,
316219a81c14SSteve Longerbeam 					&max_exp);
316319a81c14SSteve Longerbeam 		if (ret)
316419a81c14SSteve Longerbeam 			return ret;
316519a81c14SSteve Longerbeam 		ret = ov5640_get_vts(sensor);
316619a81c14SSteve Longerbeam 		if (ret < 0)
316719a81c14SSteve Longerbeam 			return ret;
316819a81c14SSteve Longerbeam 		max_exp += ret;
31696146fde3SHugues Fruchet 		ret = 0;
317019a81c14SSteve Longerbeam 
317119a81c14SSteve Longerbeam 		if (ctrls->exposure->val < max_exp)
317219a81c14SSteve Longerbeam 			ret = ov5640_set_exposure(sensor, ctrls->exposure->val);
317319a81c14SSteve Longerbeam 	}
317419a81c14SSteve Longerbeam 
317519a81c14SSteve Longerbeam 	return ret;
317619a81c14SSteve Longerbeam }
317719a81c14SSteve Longerbeam 
31783cca8ef5SHugues Fruchet static int ov5640_set_ctrl_gain(struct ov5640_dev *sensor, bool auto_gain)
317919a81c14SSteve Longerbeam {
318019a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
318119a81c14SSteve Longerbeam 	int ret = 0;
318219a81c14SSteve Longerbeam 
318319a81c14SSteve Longerbeam 	if (ctrls->auto_gain->is_new) {
31843cca8ef5SHugues Fruchet 		ret = ov5640_set_autogain(sensor, auto_gain);
318519a81c14SSteve Longerbeam 		if (ret)
318619a81c14SSteve Longerbeam 			return ret;
318719a81c14SSteve Longerbeam 	}
318819a81c14SSteve Longerbeam 
31893cca8ef5SHugues Fruchet 	if (!auto_gain && ctrls->gain->is_new)
31903cca8ef5SHugues Fruchet 		ret = ov5640_set_gain(sensor, ctrls->gain->val);
319119a81c14SSteve Longerbeam 
319219a81c14SSteve Longerbeam 	return ret;
319319a81c14SSteve Longerbeam }
319419a81c14SSteve Longerbeam 
31959f6d7bacSChen-Yu Tsai static const char * const test_pattern_menu[] = {
31969f6d7bacSChen-Yu Tsai 	"Disabled",
31979f6d7bacSChen-Yu Tsai 	"Color bars",
3198bddc5cdfSChen-Yu Tsai 	"Color bars w/ rolling bar",
3199bddc5cdfSChen-Yu Tsai 	"Color squares",
3200bddc5cdfSChen-Yu Tsai 	"Color squares w/ rolling bar",
32019f6d7bacSChen-Yu Tsai };
32029f6d7bacSChen-Yu Tsai 
3203a0c29afbSChen-Yu Tsai #define OV5640_TEST_ENABLE		BIT(7)
3204a0c29afbSChen-Yu Tsai #define OV5640_TEST_ROLLING		BIT(6)	/* rolling horizontal bar */
3205a0c29afbSChen-Yu Tsai #define OV5640_TEST_TRANSPARENT		BIT(5)
3206a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE_BW		BIT(4)	/* black & white squares */
3207a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_STANDARD	(0 << 2)
3208a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_1	(1 << 2)
3209a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_HOR_CHANGE	(2 << 2)
3210a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_2	(3 << 2)
3211a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR			(0 << 0)
3212a0c29afbSChen-Yu Tsai #define OV5640_TEST_RANDOM		(1 << 0)
3213a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE		(2 << 0)
3214a0c29afbSChen-Yu Tsai #define OV5640_TEST_BLACK		(3 << 0)
3215a0c29afbSChen-Yu Tsai 
3216a0c29afbSChen-Yu Tsai static const u8 test_pattern_val[] = {
3217a0c29afbSChen-Yu Tsai 	0,
32182aff1fc3SChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_BAR_VERT_CHANGE_1 |
3219a0c29afbSChen-Yu Tsai 		OV5640_TEST_BAR,
3220bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_ROLLING |
3221bddc5cdfSChen-Yu Tsai 		OV5640_TEST_BAR_VERT_CHANGE_1 | OV5640_TEST_BAR,
3222bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_SQUARE,
3223bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_ROLLING | OV5640_TEST_SQUARE,
3224a0c29afbSChen-Yu Tsai };
3225a0c29afbSChen-Yu Tsai 
322619a81c14SSteve Longerbeam static int ov5640_set_ctrl_test_pattern(struct ov5640_dev *sensor, int value)
322719a81c14SSteve Longerbeam {
3228a0c29afbSChen-Yu Tsai 	return ov5640_write_reg(sensor, OV5640_REG_PRE_ISP_TEST_SET1,
3229a0c29afbSChen-Yu Tsai 				test_pattern_val[value]);
323019a81c14SSteve Longerbeam }
323119a81c14SSteve Longerbeam 
32321068fecaSMylène Josserand static int ov5640_set_ctrl_light_freq(struct ov5640_dev *sensor, int value)
32331068fecaSMylène Josserand {
32341068fecaSMylène Josserand 	int ret;
32351068fecaSMylène Josserand 
32361068fecaSMylène Josserand 	ret = ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL01, BIT(7),
32371068fecaSMylène Josserand 			     (value == V4L2_CID_POWER_LINE_FREQUENCY_AUTO) ?
32381068fecaSMylène Josserand 			     0 : BIT(7));
32391068fecaSMylène Josserand 	if (ret)
32401068fecaSMylène Josserand 		return ret;
32411068fecaSMylène Josserand 
32421068fecaSMylène Josserand 	return ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL00, BIT(2),
32431068fecaSMylène Josserand 			      (value == V4L2_CID_POWER_LINE_FREQUENCY_50HZ) ?
32441068fecaSMylène Josserand 			      BIT(2) : 0);
32451068fecaSMylène Josserand }
32461068fecaSMylène Josserand 
3247ce85705aSHugues Fruchet static int ov5640_set_ctrl_hflip(struct ov5640_dev *sensor, int value)
3248ce85705aSHugues Fruchet {
3249ce85705aSHugues Fruchet 	/*
3250c3f3ba3eSHugues Fruchet 	 * If sensor is mounted upside down, mirror logic is inversed.
3251c3f3ba3eSHugues Fruchet 	 *
3252ce85705aSHugues Fruchet 	 * Sensor is a BSI (Back Side Illuminated) one,
3253ce85705aSHugues Fruchet 	 * so image captured is physically mirrored.
3254ce85705aSHugues Fruchet 	 * This is why mirror logic is inversed in
3255ce85705aSHugues Fruchet 	 * order to cancel this mirror effect.
3256ce85705aSHugues Fruchet 	 */
3257ce85705aSHugues Fruchet 
3258ce85705aSHugues Fruchet 	/*
3259ce85705aSHugues Fruchet 	 * TIMING TC REG21:
3260ce85705aSHugues Fruchet 	 * - [2]:	ISP mirror
3261ce85705aSHugues Fruchet 	 * - [1]:	Sensor mirror
3262ce85705aSHugues Fruchet 	 */
3263ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
3264ce85705aSHugues Fruchet 			      BIT(2) | BIT(1),
3265c3f3ba3eSHugues Fruchet 			      (!(value ^ sensor->upside_down)) ?
3266c3f3ba3eSHugues Fruchet 			      (BIT(2) | BIT(1)) : 0);
3267ce85705aSHugues Fruchet }
3268ce85705aSHugues Fruchet 
3269ce85705aSHugues Fruchet static int ov5640_set_ctrl_vflip(struct ov5640_dev *sensor, int value)
3270ce85705aSHugues Fruchet {
3271c3f3ba3eSHugues Fruchet 	/* If sensor is mounted upside down, flip logic is inversed */
3272c3f3ba3eSHugues Fruchet 
3273ce85705aSHugues Fruchet 	/*
3274ce85705aSHugues Fruchet 	 * TIMING TC REG20:
3275ce85705aSHugues Fruchet 	 * - [2]:	ISP vflip
3276ce85705aSHugues Fruchet 	 * - [1]:	Sensor vflip
3277ce85705aSHugues Fruchet 	 */
3278ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20,
3279ce85705aSHugues Fruchet 			      BIT(2) | BIT(1),
3280c3f3ba3eSHugues Fruchet 			      (value ^ sensor->upside_down) ?
3281c3f3ba3eSHugues Fruchet 			      (BIT(2) | BIT(1)) : 0);
3282ce85705aSHugues Fruchet }
3283ce85705aSHugues Fruchet 
3284bce93b82SJacopo Mondi static int ov5640_set_ctrl_vblank(struct ov5640_dev *sensor, int value)
3285bce93b82SJacopo Mondi {
3286bce93b82SJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
3287bce93b82SJacopo Mondi 
3288bce93b82SJacopo Mondi 	/* Update the VTOT timing register value. */
3289bce93b82SJacopo Mondi 	return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS,
3290bce93b82SJacopo Mondi 				  mode->height + value);
3291bce93b82SJacopo Mondi }
3292bce93b82SJacopo Mondi 
329319a81c14SSteve Longerbeam static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
329419a81c14SSteve Longerbeam {
329519a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
329619a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
329719a81c14SSteve Longerbeam 	int val;
329819a81c14SSteve Longerbeam 
329919a81c14SSteve Longerbeam 	/* v4l2_ctrl_lock() locks our own mutex */
330019a81c14SSteve Longerbeam 
330185644a9bSPaul Elder 	if (!pm_runtime_get_if_in_use(&sensor->i2c_client->dev))
330285644a9bSPaul Elder 		return 0;
330385644a9bSPaul Elder 
330419a81c14SSteve Longerbeam 	switch (ctrl->id) {
330519a81c14SSteve Longerbeam 	case V4L2_CID_AUTOGAIN:
330619a81c14SSteve Longerbeam 		val = ov5640_get_gain(sensor);
330719a81c14SSteve Longerbeam 		if (val < 0)
330819a81c14SSteve Longerbeam 			return val;
330919a81c14SSteve Longerbeam 		sensor->ctrls.gain->val = val;
331019a81c14SSteve Longerbeam 		break;
331119a81c14SSteve Longerbeam 	case V4L2_CID_EXPOSURE_AUTO:
331219a81c14SSteve Longerbeam 		val = ov5640_get_exposure(sensor);
331319a81c14SSteve Longerbeam 		if (val < 0)
331419a81c14SSteve Longerbeam 			return val;
331519a81c14SSteve Longerbeam 		sensor->ctrls.exposure->val = val;
331619a81c14SSteve Longerbeam 		break;
331719a81c14SSteve Longerbeam 	}
331819a81c14SSteve Longerbeam 
331985644a9bSPaul Elder 	pm_runtime_put_autosuspend(&sensor->i2c_client->dev);
332085644a9bSPaul Elder 
332119a81c14SSteve Longerbeam 	return 0;
332219a81c14SSteve Longerbeam }
332319a81c14SSteve Longerbeam 
332419a81c14SSteve Longerbeam static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl)
332519a81c14SSteve Longerbeam {
332619a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
332719a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
3328bce93b82SJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
3329bce93b82SJacopo Mondi 	const struct ov5640_timings *timings;
3330bce93b82SJacopo Mondi 	unsigned int exp_max;
333119a81c14SSteve Longerbeam 	int ret;
333219a81c14SSteve Longerbeam 
333319a81c14SSteve Longerbeam 	/* v4l2_ctrl_lock() locks our own mutex */
333419a81c14SSteve Longerbeam 
3335bce93b82SJacopo Mondi 	switch (ctrl->id) {
3336bce93b82SJacopo Mondi 	case V4L2_CID_VBLANK:
3337bce93b82SJacopo Mondi 		/* Update the exposure range to the newly programmed vblank. */
3338bce93b82SJacopo Mondi 		timings = ov5640_timings(sensor, mode);
3339bce93b82SJacopo Mondi 		exp_max = mode->height + ctrl->val - 4;
3340bce93b82SJacopo Mondi 		__v4l2_ctrl_modify_range(sensor->ctrls.exposure,
3341bce93b82SJacopo Mondi 					 sensor->ctrls.exposure->minimum,
3342bce93b82SJacopo Mondi 					 exp_max, sensor->ctrls.exposure->step,
3343bce93b82SJacopo Mondi 					 timings->vblank_def);
3344bce93b82SJacopo Mondi 		break;
3345bce93b82SJacopo Mondi 	}
3346bce93b82SJacopo Mondi 
334719a81c14SSteve Longerbeam 	/*
334819a81c14SSteve Longerbeam 	 * If the device is not powered up by the host driver do
334919a81c14SSteve Longerbeam 	 * not apply any controls to H/W at this time. Instead
335085644a9bSPaul Elder 	 * the controls will be restored at start streaming time.
335119a81c14SSteve Longerbeam 	 */
335285644a9bSPaul Elder 	if (!pm_runtime_get_if_in_use(&sensor->i2c_client->dev))
335319a81c14SSteve Longerbeam 		return 0;
335419a81c14SSteve Longerbeam 
335519a81c14SSteve Longerbeam 	switch (ctrl->id) {
335619a81c14SSteve Longerbeam 	case V4L2_CID_AUTOGAIN:
335719a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_gain(sensor, ctrl->val);
335819a81c14SSteve Longerbeam 		break;
335919a81c14SSteve Longerbeam 	case V4L2_CID_EXPOSURE_AUTO:
336019a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_exposure(sensor, ctrl->val);
336119a81c14SSteve Longerbeam 		break;
336219a81c14SSteve Longerbeam 	case V4L2_CID_AUTO_WHITE_BALANCE:
336319a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_white_balance(sensor, ctrl->val);
336419a81c14SSteve Longerbeam 		break;
336519a81c14SSteve Longerbeam 	case V4L2_CID_HUE:
336619a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_hue(sensor, ctrl->val);
336719a81c14SSteve Longerbeam 		break;
336819a81c14SSteve Longerbeam 	case V4L2_CID_CONTRAST:
336919a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_contrast(sensor, ctrl->val);
337019a81c14SSteve Longerbeam 		break;
337119a81c14SSteve Longerbeam 	case V4L2_CID_SATURATION:
337219a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_saturation(sensor, ctrl->val);
337319a81c14SSteve Longerbeam 		break;
337419a81c14SSteve Longerbeam 	case V4L2_CID_TEST_PATTERN:
337519a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_test_pattern(sensor, ctrl->val);
337619a81c14SSteve Longerbeam 		break;
33771068fecaSMylène Josserand 	case V4L2_CID_POWER_LINE_FREQUENCY:
33781068fecaSMylène Josserand 		ret = ov5640_set_ctrl_light_freq(sensor, ctrl->val);
33791068fecaSMylène Josserand 		break;
3380ce85705aSHugues Fruchet 	case V4L2_CID_HFLIP:
3381ce85705aSHugues Fruchet 		ret = ov5640_set_ctrl_hflip(sensor, ctrl->val);
3382ce85705aSHugues Fruchet 		break;
3383ce85705aSHugues Fruchet 	case V4L2_CID_VFLIP:
3384ce85705aSHugues Fruchet 		ret = ov5640_set_ctrl_vflip(sensor, ctrl->val);
3385ce85705aSHugues Fruchet 		break;
3386bce93b82SJacopo Mondi 	case V4L2_CID_VBLANK:
3387bce93b82SJacopo Mondi 		ret = ov5640_set_ctrl_vblank(sensor, ctrl->val);
3388bce93b82SJacopo Mondi 		break;
338919a81c14SSteve Longerbeam 	default:
339019a81c14SSteve Longerbeam 		ret = -EINVAL;
339119a81c14SSteve Longerbeam 		break;
339219a81c14SSteve Longerbeam 	}
339319a81c14SSteve Longerbeam 
339485644a9bSPaul Elder 	pm_runtime_put_autosuspend(&sensor->i2c_client->dev);
339585644a9bSPaul Elder 
339619a81c14SSteve Longerbeam 	return ret;
339719a81c14SSteve Longerbeam }
339819a81c14SSteve Longerbeam 
339919a81c14SSteve Longerbeam static const struct v4l2_ctrl_ops ov5640_ctrl_ops = {
340019a81c14SSteve Longerbeam 	.g_volatile_ctrl = ov5640_g_volatile_ctrl,
340119a81c14SSteve Longerbeam 	.s_ctrl = ov5640_s_ctrl,
340219a81c14SSteve Longerbeam };
340319a81c14SSteve Longerbeam 
340419a81c14SSteve Longerbeam static int ov5640_init_controls(struct ov5640_dev *sensor)
340519a81c14SSteve Longerbeam {
340622845bf2SJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
340719a81c14SSteve Longerbeam 	const struct v4l2_ctrl_ops *ops = &ov5640_ctrl_ops;
340819a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
340919a81c14SSteve Longerbeam 	struct v4l2_ctrl_handler *hdl = &ctrls->handler;
34101066fc1cSJacopo Mondi 	struct v4l2_fwnode_device_properties props;
341132979f67SJacopo Mondi 	const struct ov5640_timings *timings;
3412bce93b82SJacopo Mondi 	unsigned int max_vblank;
341332979f67SJacopo Mondi 	unsigned int hblank;
341419a81c14SSteve Longerbeam 	int ret;
341519a81c14SSteve Longerbeam 
341619a81c14SSteve Longerbeam 	v4l2_ctrl_handler_init(hdl, 32);
341719a81c14SSteve Longerbeam 
341819a81c14SSteve Longerbeam 	/* we can use our own mutex for the ctrl lock */
341919a81c14SSteve Longerbeam 	hdl->lock = &sensor->lock;
342019a81c14SSteve Longerbeam 
3421cc196e48SBenoit Parrot 	/* Clock related controls */
3422cc196e48SBenoit Parrot 	ctrls->pixel_rate = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE,
342322845bf2SJacopo Mondi 			      ov5640_pixel_rates[OV5640_NUM_PIXEL_RATES - 1],
342422845bf2SJacopo Mondi 			      ov5640_pixel_rates[0], 1,
342522845bf2SJacopo Mondi 			      ov5640_pixel_rates[mode->pixel_rate]);
3426cc196e48SBenoit Parrot 
34277a3b8d4bSJacopo Mondi 	ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops,
34287a3b8d4bSJacopo Mondi 					V4L2_CID_LINK_FREQ,
34297a3b8d4bSJacopo Mondi 					ARRAY_SIZE(ov5640_csi2_link_freqs) - 1,
34307a3b8d4bSJacopo Mondi 					OV5640_DEFAULT_LINK_FREQ,
34317a3b8d4bSJacopo Mondi 					ov5640_csi2_link_freqs);
34327a3b8d4bSJacopo Mondi 
343332979f67SJacopo Mondi 	timings = ov5640_timings(sensor, mode);
343432979f67SJacopo Mondi 	hblank = timings->htot - mode->width;
343532979f67SJacopo Mondi 	ctrls->hblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HBLANK, hblank,
343632979f67SJacopo Mondi 					  hblank, 1, hblank);
343732979f67SJacopo Mondi 
3438bce93b82SJacopo Mondi 	max_vblank = OV5640_MAX_VTS - mode->height;
3439bce93b82SJacopo Mondi 	ctrls->vblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VBLANK,
3440bce93b82SJacopo Mondi 					  OV5640_MIN_VBLANK, max_vblank,
3441bce93b82SJacopo Mondi 					  1, timings->vblank_def);
3442bce93b82SJacopo Mondi 
344319a81c14SSteve Longerbeam 	/* Auto/manual white balance */
344419a81c14SSteve Longerbeam 	ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops,
344519a81c14SSteve Longerbeam 					   V4L2_CID_AUTO_WHITE_BALANCE,
344619a81c14SSteve Longerbeam 					   0, 1, 1, 1);
344719a81c14SSteve Longerbeam 	ctrls->blue_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BLUE_BALANCE,
344819a81c14SSteve Longerbeam 						0, 4095, 1, 0);
344919a81c14SSteve Longerbeam 	ctrls->red_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_RED_BALANCE,
345019a81c14SSteve Longerbeam 					       0, 4095, 1, 0);
345119a81c14SSteve Longerbeam 	/* Auto/manual exposure */
345219a81c14SSteve Longerbeam 	ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops,
345319a81c14SSteve Longerbeam 						 V4L2_CID_EXPOSURE_AUTO,
345419a81c14SSteve Longerbeam 						 V4L2_EXPOSURE_MANUAL, 0,
345519a81c14SSteve Longerbeam 						 V4L2_EXPOSURE_AUTO);
345619a81c14SSteve Longerbeam 	ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
345719a81c14SSteve Longerbeam 					    0, 65535, 1, 0);
345819a81c14SSteve Longerbeam 	/* Auto/manual gain */
345919a81c14SSteve Longerbeam 	ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN,
346019a81c14SSteve Longerbeam 					     0, 1, 1, 1);
346119a81c14SSteve Longerbeam 	ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN,
346219a81c14SSteve Longerbeam 					0, 1023, 1, 0);
346319a81c14SSteve Longerbeam 
346419a81c14SSteve Longerbeam 	ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION,
346519a81c14SSteve Longerbeam 					      0, 255, 1, 64);
346619a81c14SSteve Longerbeam 	ctrls->hue = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HUE,
346719a81c14SSteve Longerbeam 				       0, 359, 1, 0);
346819a81c14SSteve Longerbeam 	ctrls->contrast = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST,
346919a81c14SSteve Longerbeam 					    0, 255, 1, 0);
347019a81c14SSteve Longerbeam 	ctrls->test_pattern =
347119a81c14SSteve Longerbeam 		v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN,
347219a81c14SSteve Longerbeam 					     ARRAY_SIZE(test_pattern_menu) - 1,
347319a81c14SSteve Longerbeam 					     0, 0, test_pattern_menu);
3474ce85705aSHugues Fruchet 	ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP,
3475ce85705aSHugues Fruchet 					 0, 1, 1, 0);
3476ce85705aSHugues Fruchet 	ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP,
3477ce85705aSHugues Fruchet 					 0, 1, 1, 0);
347819a81c14SSteve Longerbeam 
34791068fecaSMylène Josserand 	ctrls->light_freq =
34801068fecaSMylène Josserand 		v4l2_ctrl_new_std_menu(hdl, ops,
34811068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY,
34821068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
34831068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
34841068fecaSMylène Josserand 
348519a81c14SSteve Longerbeam 	if (hdl->error) {
348619a81c14SSteve Longerbeam 		ret = hdl->error;
348719a81c14SSteve Longerbeam 		goto free_ctrls;
348819a81c14SSteve Longerbeam 	}
348919a81c14SSteve Longerbeam 
34901066fc1cSJacopo Mondi 	ret = v4l2_fwnode_device_parse(&sensor->i2c_client->dev, &props);
34911066fc1cSJacopo Mondi 	if (ret)
34921066fc1cSJacopo Mondi 		goto free_ctrls;
34931066fc1cSJacopo Mondi 
34941066fc1cSJacopo Mondi 	if (props.rotation == 180)
34951066fc1cSJacopo Mondi 		sensor->upside_down = true;
34961066fc1cSJacopo Mondi 
34971066fc1cSJacopo Mondi 	ret = v4l2_ctrl_new_fwnode_properties(hdl, ops, &props);
34981066fc1cSJacopo Mondi 	if (ret)
34991066fc1cSJacopo Mondi 		goto free_ctrls;
35001066fc1cSJacopo Mondi 
3501cc196e48SBenoit Parrot 	ctrls->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY;
35027a3b8d4bSJacopo Mondi 	ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
350332979f67SJacopo Mondi 	ctrls->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
350419a81c14SSteve Longerbeam 	ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE;
350519a81c14SSteve Longerbeam 	ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE;
350619a81c14SSteve Longerbeam 
350719a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false);
350819a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(2, &ctrls->auto_gain, 0, true);
350919a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(2, &ctrls->auto_exp, 1, true);
351019a81c14SSteve Longerbeam 
351119a81c14SSteve Longerbeam 	sensor->sd.ctrl_handler = hdl;
351219a81c14SSteve Longerbeam 	return 0;
351319a81c14SSteve Longerbeam 
351419a81c14SSteve Longerbeam free_ctrls:
351519a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(hdl);
351619a81c14SSteve Longerbeam 	return ret;
351719a81c14SSteve Longerbeam }
351819a81c14SSteve Longerbeam 
351919a81c14SSteve Longerbeam static int ov5640_enum_frame_size(struct v4l2_subdev *sd,
35200d346d2aSTomi Valkeinen 				  struct v4l2_subdev_state *sd_state,
352119a81c14SSteve Longerbeam 				  struct v4l2_subdev_frame_size_enum *fse)
352219a81c14SSteve Longerbeam {
3523a89f14bbSJacopo Mondi 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
3524a89f14bbSJacopo Mondi 	u32 bpp = ov5640_code_to_bpp(sensor, fse->code);
35257dcb3a2fSJacopo Mondi 	unsigned int index = fse->index;
35267dcb3a2fSJacopo Mondi 
352719a81c14SSteve Longerbeam 	if (fse->pad != 0)
352819a81c14SSteve Longerbeam 		return -EINVAL;
35297dcb3a2fSJacopo Mondi 	if (!bpp)
353019a81c14SSteve Longerbeam 		return -EINVAL;
353119a81c14SSteve Longerbeam 
35327dcb3a2fSJacopo Mondi 	/* Only low-resolution modes are supported for 24bpp formats. */
35337dcb3a2fSJacopo Mondi 	if (bpp == 24 && index >= OV5640_MODE_720P_1280_720)
35347dcb3a2fSJacopo Mondi 		return -EINVAL;
35357dcb3a2fSJacopo Mondi 
35367dcb3a2fSJacopo Mondi 	/* FIXME: Low resolution modes don't work in 8bpp formats. */
35377dcb3a2fSJacopo Mondi 	if (bpp == 8)
35387dcb3a2fSJacopo Mondi 		index += OV5640_MODE_720P_1280_720;
35397dcb3a2fSJacopo Mondi 
35407dcb3a2fSJacopo Mondi 	if (index >= OV5640_NUM_MODES)
35417dcb3a2fSJacopo Mondi 		return -EINVAL;
35427dcb3a2fSJacopo Mondi 
35437dcb3a2fSJacopo Mondi 	fse->min_width = ov5640_mode_data[index].width;
354441d8d7f5SHugues Fruchet 	fse->max_width = fse->min_width;
35457dcb3a2fSJacopo Mondi 	fse->min_height = ov5640_mode_data[index].height;
354641d8d7f5SHugues Fruchet 	fse->max_height = fse->min_height;
354719a81c14SSteve Longerbeam 
354819a81c14SSteve Longerbeam 	return 0;
354919a81c14SSteve Longerbeam }
355019a81c14SSteve Longerbeam 
355119a81c14SSteve Longerbeam static int ov5640_enum_frame_interval(
355219a81c14SSteve Longerbeam 	struct v4l2_subdev *sd,
35530d346d2aSTomi Valkeinen 	struct v4l2_subdev_state *sd_state,
355419a81c14SSteve Longerbeam 	struct v4l2_subdev_frame_interval_enum *fie)
355519a81c14SSteve Longerbeam {
355619a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
3557*f33b56d3SGuoniu.zhou 	const struct ov5640_mode_info *mode;
355819a81c14SSteve Longerbeam 	struct v4l2_fract tpf;
355919a81c14SSteve Longerbeam 	int ret;
356019a81c14SSteve Longerbeam 
356119a81c14SSteve Longerbeam 	if (fie->pad != 0)
356219a81c14SSteve Longerbeam 		return -EINVAL;
356319a81c14SSteve Longerbeam 	if (fie->index >= OV5640_NUM_FRAMERATES)
356419a81c14SSteve Longerbeam 		return -EINVAL;
356519a81c14SSteve Longerbeam 
3566*f33b56d3SGuoniu.zhou 	mode = ov5640_find_mode(sensor, fie->width, fie->height, false);
3567*f33b56d3SGuoniu.zhou 	if (!mode)
3568*f33b56d3SGuoniu.zhou 		return -EINVAL;
3569*f33b56d3SGuoniu.zhou 
357019a81c14SSteve Longerbeam 	tpf.numerator = 1;
357119a81c14SSteve Longerbeam 	tpf.denominator = ov5640_framerates[fie->index];
357219a81c14SSteve Longerbeam 
3573*f33b56d3SGuoniu.zhou 	ret = ov5640_try_frame_interval(sensor, &tpf, mode);
357419a81c14SSteve Longerbeam 	if (ret < 0)
357519a81c14SSteve Longerbeam 		return -EINVAL;
357619a81c14SSteve Longerbeam 
357719a81c14SSteve Longerbeam 	fie->interval = tpf;
357819a81c14SSteve Longerbeam 	return 0;
357919a81c14SSteve Longerbeam }
358019a81c14SSteve Longerbeam 
358119a81c14SSteve Longerbeam static int ov5640_g_frame_interval(struct v4l2_subdev *sd,
358219a81c14SSteve Longerbeam 				   struct v4l2_subdev_frame_interval *fi)
358319a81c14SSteve Longerbeam {
358419a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
358519a81c14SSteve Longerbeam 
358619a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
358719a81c14SSteve Longerbeam 	fi->interval = sensor->frame_interval;
358819a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
358919a81c14SSteve Longerbeam 
359019a81c14SSteve Longerbeam 	return 0;
359119a81c14SSteve Longerbeam }
359219a81c14SSteve Longerbeam 
359319a81c14SSteve Longerbeam static int ov5640_s_frame_interval(struct v4l2_subdev *sd,
359419a81c14SSteve Longerbeam 				   struct v4l2_subdev_frame_interval *fi)
359519a81c14SSteve Longerbeam {
359619a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
359719a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
359819a81c14SSteve Longerbeam 	int frame_rate, ret = 0;
359919a81c14SSteve Longerbeam 
360019a81c14SSteve Longerbeam 	if (fi->pad != 0)
360119a81c14SSteve Longerbeam 		return -EINVAL;
360219a81c14SSteve Longerbeam 
360319a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
360419a81c14SSteve Longerbeam 
360519a81c14SSteve Longerbeam 	if (sensor->streaming) {
360619a81c14SSteve Longerbeam 		ret = -EBUSY;
360719a81c14SSteve Longerbeam 		goto out;
360819a81c14SSteve Longerbeam 	}
360919a81c14SSteve Longerbeam 
361019a81c14SSteve Longerbeam 	mode = sensor->current_mode;
361119a81c14SSteve Longerbeam 
3612*f33b56d3SGuoniu.zhou 	frame_rate = ov5640_try_frame_interval(sensor, &fi->interval, mode);
3613e823fb16SMaxime Ripard 	if (frame_rate < 0) {
3614e823fb16SMaxime Ripard 		/* Always return a valid frame interval value */
3615e823fb16SMaxime Ripard 		fi->interval = sensor->frame_interval;
3616e823fb16SMaxime Ripard 		goto out;
3617e823fb16SMaxime Ripard 	}
361819a81c14SSteve Longerbeam 
3619b6ae5022SJacopo Mondi 	mode = ov5640_find_mode(sensor, mode->width, mode->height, true);
36203c4a7372SHugues Fruchet 	if (!mode) {
36213c4a7372SHugues Fruchet 		ret = -EINVAL;
36223c4a7372SHugues Fruchet 		goto out;
36233c4a7372SHugues Fruchet 	}
36243c4a7372SHugues Fruchet 
3625b6ae5022SJacopo Mondi 	if (ov5640_framerates[frame_rate] > ov5640_framerates[mode->max_fps]) {
3626b6ae5022SJacopo Mondi 		ret = -EINVAL;
3627b6ae5022SJacopo Mondi 		goto out;
3628b6ae5022SJacopo Mondi 	}
3629b6ae5022SJacopo Mondi 
36300929983eSHugues Fruchet 	if (mode != sensor->current_mode ||
36310929983eSHugues Fruchet 	    frame_rate != sensor->current_fr) {
36320929983eSHugues Fruchet 		sensor->current_fr = frame_rate;
36330929983eSHugues Fruchet 		sensor->frame_interval = fi->interval;
36343c4a7372SHugues Fruchet 		sensor->current_mode = mode;
363519a81c14SSteve Longerbeam 		sensor->pending_mode_change = true;
3636cc196e48SBenoit Parrot 
363719f2e3e6SHugues Fruchet 		ov5640_update_pixel_rate(sensor);
36386949d864SHugues Fruchet 	}
363919a81c14SSteve Longerbeam out:
364019a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
364119a81c14SSteve Longerbeam 	return ret;
364219a81c14SSteve Longerbeam }
364319a81c14SSteve Longerbeam 
364419a81c14SSteve Longerbeam static int ov5640_enum_mbus_code(struct v4l2_subdev *sd,
36450d346d2aSTomi Valkeinen 				 struct v4l2_subdev_state *sd_state,
364619a81c14SSteve Longerbeam 				 struct v4l2_subdev_mbus_code_enum *code)
364719a81c14SSteve Longerbeam {
3648a89f14bbSJacopo Mondi 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
3649a89f14bbSJacopo Mondi 	const struct ov5640_pixfmt *formats;
3650a89f14bbSJacopo Mondi 	unsigned int num_formats;
3651a89f14bbSJacopo Mondi 
3652a89f14bbSJacopo Mondi 	if (ov5640_is_csi2(sensor)) {
3653a89f14bbSJacopo Mondi 		formats = ov5640_csi2_formats;
3654a89f14bbSJacopo Mondi 		num_formats = ARRAY_SIZE(ov5640_csi2_formats) - 1;
3655a89f14bbSJacopo Mondi 	} else {
3656a89f14bbSJacopo Mondi 		formats = ov5640_dvp_formats;
3657a89f14bbSJacopo Mondi 		num_formats = ARRAY_SIZE(ov5640_dvp_formats) - 1;
3658a89f14bbSJacopo Mondi 	}
3659a89f14bbSJacopo Mondi 
3660a89f14bbSJacopo Mondi 	if (code->index >= num_formats)
366119a81c14SSteve Longerbeam 		return -EINVAL;
366219a81c14SSteve Longerbeam 
3663a89f14bbSJacopo Mondi 	code->code = formats[code->index].code;
3664a89f14bbSJacopo Mondi 
366519a81c14SSteve Longerbeam 	return 0;
366619a81c14SSteve Longerbeam }
366719a81c14SSteve Longerbeam 
366819a81c14SSteve Longerbeam static int ov5640_s_stream(struct v4l2_subdev *sd, int enable)
366919a81c14SSteve Longerbeam {
367019a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
367119a81c14SSteve Longerbeam 	int ret = 0;
367219a81c14SSteve Longerbeam 
367385644a9bSPaul Elder 	if (enable) {
367485644a9bSPaul Elder 		ret = pm_runtime_resume_and_get(&sensor->i2c_client->dev);
367585644a9bSPaul Elder 		if (ret < 0)
367685644a9bSPaul Elder 			return ret;
367785644a9bSPaul Elder 
367885644a9bSPaul Elder 		ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
367985644a9bSPaul Elder 		if (ret) {
368085644a9bSPaul Elder 			pm_runtime_put(&sensor->i2c_client->dev);
368185644a9bSPaul Elder 			return ret;
368285644a9bSPaul Elder 		}
368385644a9bSPaul Elder 	}
368485644a9bSPaul Elder 
368519a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
368619a81c14SSteve Longerbeam 
368719a81c14SSteve Longerbeam 	if (sensor->streaming == !enable) {
368819a81c14SSteve Longerbeam 		if (enable && sensor->pending_mode_change) {
3689985cdcb0SHugues Fruchet 			ret = ov5640_set_mode(sensor);
369019a81c14SSteve Longerbeam 			if (ret)
369119a81c14SSteve Longerbeam 				goto out;
3692fb98e29fSHugues Fruchet 		}
3693e3ee691dSHugues Fruchet 
3694fb98e29fSHugues Fruchet 		if (enable && sensor->pending_fmt_change) {
3695e3ee691dSHugues Fruchet 			ret = ov5640_set_framefmt(sensor, &sensor->fmt);
3696e3ee691dSHugues Fruchet 			if (ret)
3697e3ee691dSHugues Fruchet 				goto out;
3698fb98e29fSHugues Fruchet 			sensor->pending_fmt_change = false;
369919a81c14SSteve Longerbeam 		}
370019a81c14SSteve Longerbeam 
37018e823f5cSJacopo Mondi 		if (ov5640_is_csi2(sensor))
3702f22996dbSHugues Fruchet 			ret = ov5640_set_stream_mipi(sensor, enable);
3703f22996dbSHugues Fruchet 		else
3704f22996dbSHugues Fruchet 			ret = ov5640_set_stream_dvp(sensor, enable);
3705f22996dbSHugues Fruchet 
370619a81c14SSteve Longerbeam 		if (!ret)
370719a81c14SSteve Longerbeam 			sensor->streaming = enable;
370819a81c14SSteve Longerbeam 	}
370985644a9bSPaul Elder 
371019a81c14SSteve Longerbeam out:
371119a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
371285644a9bSPaul Elder 
371385644a9bSPaul Elder 	if (!enable || ret)
371485644a9bSPaul Elder 		pm_runtime_put_autosuspend(&sensor->i2c_client->dev);
371585644a9bSPaul Elder 
371619a81c14SSteve Longerbeam 	return ret;
371719a81c14SSteve Longerbeam }
371819a81c14SSteve Longerbeam 
371990b0f355SJacopo Mondi static int ov5640_init_cfg(struct v4l2_subdev *sd,
372090b0f355SJacopo Mondi 			   struct v4l2_subdev_state *state)
372190b0f355SJacopo Mondi {
372290b0f355SJacopo Mondi 	struct v4l2_mbus_framefmt *fmt =
372390b0f355SJacopo Mondi 				v4l2_subdev_get_try_format(sd, state, 0);
372466ed85ebSJacopo Mondi 	struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, state, 0);
372590b0f355SJacopo Mondi 
372690b0f355SJacopo Mondi 	*fmt = ov5640_default_fmt;
372790b0f355SJacopo Mondi 
372866ed85ebSJacopo Mondi 	crop->left = OV5640_PIXEL_ARRAY_LEFT;
372966ed85ebSJacopo Mondi 	crop->top = OV5640_PIXEL_ARRAY_TOP;
373066ed85ebSJacopo Mondi 	crop->width = OV5640_PIXEL_ARRAY_WIDTH;
373166ed85ebSJacopo Mondi 	crop->height = OV5640_PIXEL_ARRAY_HEIGHT;
373266ed85ebSJacopo Mondi 
373390b0f355SJacopo Mondi 	return 0;
373490b0f355SJacopo Mondi }
373590b0f355SJacopo Mondi 
373619a81c14SSteve Longerbeam static const struct v4l2_subdev_core_ops ov5640_core_ops = {
37372d18fbc5SAkinobu Mita 	.log_status = v4l2_ctrl_subdev_log_status,
37382d18fbc5SAkinobu Mita 	.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
37392d18fbc5SAkinobu Mita 	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
374019a81c14SSteve Longerbeam };
374119a81c14SSteve Longerbeam 
374219a81c14SSteve Longerbeam static const struct v4l2_subdev_video_ops ov5640_video_ops = {
374319a81c14SSteve Longerbeam 	.g_frame_interval = ov5640_g_frame_interval,
374419a81c14SSteve Longerbeam 	.s_frame_interval = ov5640_s_frame_interval,
374519a81c14SSteve Longerbeam 	.s_stream = ov5640_s_stream,
374619a81c14SSteve Longerbeam };
374719a81c14SSteve Longerbeam 
374819a81c14SSteve Longerbeam static const struct v4l2_subdev_pad_ops ov5640_pad_ops = {
374990b0f355SJacopo Mondi 	.init_cfg = ov5640_init_cfg,
375019a81c14SSteve Longerbeam 	.enum_mbus_code = ov5640_enum_mbus_code,
375119a81c14SSteve Longerbeam 	.get_fmt = ov5640_get_fmt,
375219a81c14SSteve Longerbeam 	.set_fmt = ov5640_set_fmt,
375366ed85ebSJacopo Mondi 	.get_selection = ov5640_get_selection,
375419a81c14SSteve Longerbeam 	.enum_frame_size = ov5640_enum_frame_size,
375519a81c14SSteve Longerbeam 	.enum_frame_interval = ov5640_enum_frame_interval,
375619a81c14SSteve Longerbeam };
375719a81c14SSteve Longerbeam 
375819a81c14SSteve Longerbeam static const struct v4l2_subdev_ops ov5640_subdev_ops = {
375919a81c14SSteve Longerbeam 	.core = &ov5640_core_ops,
376019a81c14SSteve Longerbeam 	.video = &ov5640_video_ops,
376119a81c14SSteve Longerbeam 	.pad = &ov5640_pad_ops,
376219a81c14SSteve Longerbeam };
376319a81c14SSteve Longerbeam 
376419a81c14SSteve Longerbeam static int ov5640_get_regulators(struct ov5640_dev *sensor)
376519a81c14SSteve Longerbeam {
376619a81c14SSteve Longerbeam 	int i;
376719a81c14SSteve Longerbeam 
376819a81c14SSteve Longerbeam 	for (i = 0; i < OV5640_NUM_SUPPLIES; i++)
376919a81c14SSteve Longerbeam 		sensor->supplies[i].supply = ov5640_supply_name[i];
377019a81c14SSteve Longerbeam 
377119a81c14SSteve Longerbeam 	return devm_regulator_bulk_get(&sensor->i2c_client->dev,
377219a81c14SSteve Longerbeam 				       OV5640_NUM_SUPPLIES,
377319a81c14SSteve Longerbeam 				       sensor->supplies);
377419a81c14SSteve Longerbeam }
377519a81c14SSteve Longerbeam 
37760f7acb52SHugues Fruchet static int ov5640_check_chip_id(struct ov5640_dev *sensor)
37770f7acb52SHugues Fruchet {
37780f7acb52SHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
37790f7acb52SHugues Fruchet 	int ret = 0;
37800f7acb52SHugues Fruchet 	u16 chip_id;
37810f7acb52SHugues Fruchet 
37820f7acb52SHugues Fruchet 	ret = ov5640_read_reg16(sensor, OV5640_REG_CHIP_ID, &chip_id);
37830f7acb52SHugues Fruchet 	if (ret) {
37840f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to read chip identifier\n",
37850f7acb52SHugues Fruchet 			__func__);
378685644a9bSPaul Elder 		return ret;
37870f7acb52SHugues Fruchet 	}
37880f7acb52SHugues Fruchet 
37890f7acb52SHugues Fruchet 	if (chip_id != 0x5640) {
37900f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: wrong chip identifier, expected 0x5640, got 0x%x\n",
37910f7acb52SHugues Fruchet 			__func__, chip_id);
379285644a9bSPaul Elder 		return -ENXIO;
37930f7acb52SHugues Fruchet 	}
37940f7acb52SHugues Fruchet 
379585644a9bSPaul Elder 	return 0;
37960f7acb52SHugues Fruchet }
37970f7acb52SHugues Fruchet 
3798e6714993SKieran Bingham static int ov5640_probe(struct i2c_client *client)
379919a81c14SSteve Longerbeam {
380019a81c14SSteve Longerbeam 	struct device *dev = &client->dev;
380119a81c14SSteve Longerbeam 	struct fwnode_handle *endpoint;
380219a81c14SSteve Longerbeam 	struct ov5640_dev *sensor;
380319a81c14SSteve Longerbeam 	int ret;
380419a81c14SSteve Longerbeam 
380519a81c14SSteve Longerbeam 	sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
380619a81c14SSteve Longerbeam 	if (!sensor)
380719a81c14SSteve Longerbeam 		return -ENOMEM;
380819a81c14SSteve Longerbeam 
380919a81c14SSteve Longerbeam 	sensor->i2c_client = client;
3810fb98e29fSHugues Fruchet 
3811fb98e29fSHugues Fruchet 	/*
3812fb98e29fSHugues Fruchet 	 * default init sequence initialize sensor to
3813fb98e29fSHugues Fruchet 	 * YUV422 UYVY VGA@30fps
3814fb98e29fSHugues Fruchet 	 */
381590b0f355SJacopo Mondi 	sensor->fmt = ov5640_default_fmt;
381619a81c14SSteve Longerbeam 	sensor->frame_interval.numerator = 1;
381719a81c14SSteve Longerbeam 	sensor->frame_interval.denominator = ov5640_framerates[OV5640_30_FPS];
381819a81c14SSteve Longerbeam 	sensor->current_fr = OV5640_30_FPS;
381919a81c14SSteve Longerbeam 	sensor->current_mode =
3820086c25f8SMaxime Ripard 		&ov5640_mode_data[OV5640_MODE_VGA_640_480];
3821985cdcb0SHugues Fruchet 	sensor->last_mode = sensor->current_mode;
3822d7b41196SGuoniu.zhou 	sensor->current_link_freq =
3823d7b41196SGuoniu.zhou 		ov5640_csi2_link_freqs[OV5640_DEFAULT_LINK_FREQ];
382419a81c14SSteve Longerbeam 
382519a81c14SSteve Longerbeam 	sensor->ae_target = 52;
382619a81c14SSteve Longerbeam 
3827ce96bcf5SSakari Ailus 	endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev),
3828ce96bcf5SSakari Ailus 						  NULL);
382919a81c14SSteve Longerbeam 	if (!endpoint) {
383019a81c14SSteve Longerbeam 		dev_err(dev, "endpoint node not found\n");
383119a81c14SSteve Longerbeam 		return -EINVAL;
383219a81c14SSteve Longerbeam 	}
383319a81c14SSteve Longerbeam 
383419a81c14SSteve Longerbeam 	ret = v4l2_fwnode_endpoint_parse(endpoint, &sensor->ep);
383519a81c14SSteve Longerbeam 	fwnode_handle_put(endpoint);
383619a81c14SSteve Longerbeam 	if (ret) {
383719a81c14SSteve Longerbeam 		dev_err(dev, "Could not parse endpoint\n");
383819a81c14SSteve Longerbeam 		return ret;
383919a81c14SSteve Longerbeam 	}
384019a81c14SSteve Longerbeam 
38412c61e48dSLad Prabhakar 	if (sensor->ep.bus_type != V4L2_MBUS_PARALLEL &&
38422c61e48dSLad Prabhakar 	    sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY &&
38432c61e48dSLad Prabhakar 	    sensor->ep.bus_type != V4L2_MBUS_BT656) {
38442c61e48dSLad Prabhakar 		dev_err(dev, "Unsupported bus type %d\n", sensor->ep.bus_type);
38452c61e48dSLad Prabhakar 		return -EINVAL;
38462c61e48dSLad Prabhakar 	}
38472c61e48dSLad Prabhakar 
384819a81c14SSteve Longerbeam 	/* get system clock (xclk) */
384919a81c14SSteve Longerbeam 	sensor->xclk = devm_clk_get(dev, "xclk");
385019a81c14SSteve Longerbeam 	if (IS_ERR(sensor->xclk)) {
385119a81c14SSteve Longerbeam 		dev_err(dev, "failed to get xclk\n");
385219a81c14SSteve Longerbeam 		return PTR_ERR(sensor->xclk);
385319a81c14SSteve Longerbeam 	}
385419a81c14SSteve Longerbeam 
385519a81c14SSteve Longerbeam 	sensor->xclk_freq = clk_get_rate(sensor->xclk);
385619a81c14SSteve Longerbeam 	if (sensor->xclk_freq < OV5640_XCLK_MIN ||
385719a81c14SSteve Longerbeam 	    sensor->xclk_freq > OV5640_XCLK_MAX) {
385819a81c14SSteve Longerbeam 		dev_err(dev, "xclk frequency out of range: %d Hz\n",
385919a81c14SSteve Longerbeam 			sensor->xclk_freq);
386019a81c14SSteve Longerbeam 		return -EINVAL;
386119a81c14SSteve Longerbeam 	}
386219a81c14SSteve Longerbeam 
386319a81c14SSteve Longerbeam 	/* request optional power down pin */
386419a81c14SSteve Longerbeam 	sensor->pwdn_gpio = devm_gpiod_get_optional(dev, "powerdown",
386519a81c14SSteve Longerbeam 						    GPIOD_OUT_HIGH);
38668791a102SFabio Estevam 	if (IS_ERR(sensor->pwdn_gpio))
38678791a102SFabio Estevam 		return PTR_ERR(sensor->pwdn_gpio);
38688791a102SFabio Estevam 
386919a81c14SSteve Longerbeam 	/* request optional reset pin */
387019a81c14SSteve Longerbeam 	sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset",
387119a81c14SSteve Longerbeam 						     GPIOD_OUT_HIGH);
38728791a102SFabio Estevam 	if (IS_ERR(sensor->reset_gpio))
38738791a102SFabio Estevam 		return PTR_ERR(sensor->reset_gpio);
387419a81c14SSteve Longerbeam 
387519a81c14SSteve Longerbeam 	v4l2_i2c_subdev_init(&sensor->sd, client, &ov5640_subdev_ops);
387619a81c14SSteve Longerbeam 
38772d18fbc5SAkinobu Mita 	sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
38782d18fbc5SAkinobu Mita 			    V4L2_SUBDEV_FL_HAS_EVENTS;
387919a81c14SSteve Longerbeam 	sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
388019a81c14SSteve Longerbeam 	sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
388119a81c14SSteve Longerbeam 	ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
388219a81c14SSteve Longerbeam 	if (ret)
388319a81c14SSteve Longerbeam 		return ret;
388419a81c14SSteve Longerbeam 
388519a81c14SSteve Longerbeam 	ret = ov5640_get_regulators(sensor);
388619a81c14SSteve Longerbeam 	if (ret)
388785644a9bSPaul Elder 		goto entity_cleanup;
388819a81c14SSteve Longerbeam 
388919a81c14SSteve Longerbeam 	mutex_init(&sensor->lock);
389019a81c14SSteve Longerbeam 
389119a81c14SSteve Longerbeam 	ret = ov5640_init_controls(sensor);
389219a81c14SSteve Longerbeam 	if (ret)
389319a81c14SSteve Longerbeam 		goto entity_cleanup;
389419a81c14SSteve Longerbeam 
389585644a9bSPaul Elder 	ret = ov5640_sensor_resume(dev);
389685644a9bSPaul Elder 	if (ret) {
389785644a9bSPaul Elder 		dev_err(dev, "failed to power on\n");
389885644a9bSPaul Elder 		goto entity_cleanup;
389985644a9bSPaul Elder 	}
390085644a9bSPaul Elder 
390185644a9bSPaul Elder 	pm_runtime_set_active(dev);
390285644a9bSPaul Elder 	pm_runtime_get_noresume(dev);
390385644a9bSPaul Elder 	pm_runtime_enable(dev);
390485644a9bSPaul Elder 
390585644a9bSPaul Elder 	ret = ov5640_check_chip_id(sensor);
390685644a9bSPaul Elder 	if (ret)
390785644a9bSPaul Elder 		goto err_pm_runtime;
390885644a9bSPaul Elder 
390915786f7bSSakari Ailus 	ret = v4l2_async_register_subdev_sensor(&sensor->sd);
391019a81c14SSteve Longerbeam 	if (ret)
391185644a9bSPaul Elder 		goto err_pm_runtime;
391285644a9bSPaul Elder 
391385644a9bSPaul Elder 	pm_runtime_set_autosuspend_delay(dev, 1000);
391485644a9bSPaul Elder 	pm_runtime_use_autosuspend(dev);
391585644a9bSPaul Elder 	pm_runtime_put_autosuspend(dev);
391619a81c14SSteve Longerbeam 
391719a81c14SSteve Longerbeam 	return 0;
391819a81c14SSteve Longerbeam 
391985644a9bSPaul Elder err_pm_runtime:
392085644a9bSPaul Elder 	pm_runtime_put_noidle(dev);
392185644a9bSPaul Elder 	pm_runtime_disable(dev);
392219a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
392385644a9bSPaul Elder 	ov5640_sensor_suspend(dev);
392419a81c14SSteve Longerbeam entity_cleanup:
392519a81c14SSteve Longerbeam 	media_entity_cleanup(&sensor->sd.entity);
3926bfcba38dSTomi Valkeinen 	mutex_destroy(&sensor->lock);
392719a81c14SSteve Longerbeam 	return ret;
392819a81c14SSteve Longerbeam }
392919a81c14SSteve Longerbeam 
3930ed5c2f5fSUwe Kleine-König static void ov5640_remove(struct i2c_client *client)
393119a81c14SSteve Longerbeam {
393219a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
393319a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
393485644a9bSPaul Elder 	struct device *dev = &client->dev;
393585644a9bSPaul Elder 
393685644a9bSPaul Elder 	pm_runtime_disable(dev);
393785644a9bSPaul Elder 	if (!pm_runtime_status_suspended(dev))
393885644a9bSPaul Elder 		ov5640_sensor_suspend(dev);
393985644a9bSPaul Elder 	pm_runtime_set_suspended(dev);
394019a81c14SSteve Longerbeam 
394119a81c14SSteve Longerbeam 	v4l2_async_unregister_subdev(&sensor->sd);
394219a81c14SSteve Longerbeam 	media_entity_cleanup(&sensor->sd.entity);
394319a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
3944bfcba38dSTomi Valkeinen 	mutex_destroy(&sensor->lock);
394519a81c14SSteve Longerbeam }
394619a81c14SSteve Longerbeam 
394785644a9bSPaul Elder static const struct dev_pm_ops ov5640_pm_ops = {
394885644a9bSPaul Elder 	SET_RUNTIME_PM_OPS(ov5640_sensor_suspend, ov5640_sensor_resume, NULL)
394985644a9bSPaul Elder };
395085644a9bSPaul Elder 
395119a81c14SSteve Longerbeam static const struct i2c_device_id ov5640_id[] = {
395219a81c14SSteve Longerbeam 	{"ov5640", 0},
395319a81c14SSteve Longerbeam 	{},
395419a81c14SSteve Longerbeam };
395519a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(i2c, ov5640_id);
395619a81c14SSteve Longerbeam 
395719a81c14SSteve Longerbeam static const struct of_device_id ov5640_dt_ids[] = {
395819a81c14SSteve Longerbeam 	{ .compatible = "ovti,ov5640" },
395919a81c14SSteve Longerbeam 	{ /* sentinel */ }
396019a81c14SSteve Longerbeam };
396119a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(of, ov5640_dt_ids);
396219a81c14SSteve Longerbeam 
396319a81c14SSteve Longerbeam static struct i2c_driver ov5640_i2c_driver = {
396419a81c14SSteve Longerbeam 	.driver = {
396519a81c14SSteve Longerbeam 		.name  = "ov5640",
396619a81c14SSteve Longerbeam 		.of_match_table	= ov5640_dt_ids,
396785644a9bSPaul Elder 		.pm = &ov5640_pm_ops,
396819a81c14SSteve Longerbeam 	},
396919a81c14SSteve Longerbeam 	.id_table = ov5640_id,
3970e6714993SKieran Bingham 	.probe_new = ov5640_probe,
397119a81c14SSteve Longerbeam 	.remove   = ov5640_remove,
397219a81c14SSteve Longerbeam };
397319a81c14SSteve Longerbeam 
397419a81c14SSteve Longerbeam module_i2c_driver(ov5640_i2c_driver);
397519a81c14SSteve Longerbeam 
397619a81c14SSteve Longerbeam MODULE_DESCRIPTION("OV5640 MIPI Camera Subdev Driver");
397719a81c14SSteve Longerbeam MODULE_LICENSE("GPL");
3978