xref: /openbmc/linux/drivers/media/i2c/ov5640.c (revision e13064a3)
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 
52368453b02SGuoniu.zhou static const struct v4l2_mbus_framefmt ov5640_csi2_default_fmt = {
52468453b02SGuoniu.zhou 	.code = MEDIA_BUS_FMT_UYVY8_1X16,
52568453b02SGuoniu.zhou 	.width = 640,
52668453b02SGuoniu.zhou 	.height = 480,
52768453b02SGuoniu.zhou 	.colorspace = V4L2_COLORSPACE_SRGB,
52868453b02SGuoniu.zhou 	.ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SRGB),
52968453b02SGuoniu.zhou 	.quantization = V4L2_QUANTIZATION_FULL_RANGE,
53068453b02SGuoniu.zhou 	.xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SRGB),
53168453b02SGuoniu.zhou 	.field = V4L2_FIELD_NONE,
53268453b02SGuoniu.zhou };
53368453b02SGuoniu.zhou 
53468453b02SGuoniu.zhou static const struct v4l2_mbus_framefmt ov5640_dvp_default_fmt = {
53590b0f355SJacopo Mondi 	.code = MEDIA_BUS_FMT_UYVY8_2X8,
53690b0f355SJacopo Mondi 	.width = 640,
53790b0f355SJacopo Mondi 	.height = 480,
53890b0f355SJacopo Mondi 	.colorspace = V4L2_COLORSPACE_SRGB,
53990b0f355SJacopo Mondi 	.ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SRGB),
54090b0f355SJacopo Mondi 	.quantization = V4L2_QUANTIZATION_FULL_RANGE,
54190b0f355SJacopo Mondi 	.xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SRGB),
54290b0f355SJacopo Mondi 	.field = V4L2_FIELD_NONE,
54390b0f355SJacopo Mondi };
54490b0f355SJacopo Mondi 
545e4359019SJacopo Mondi static const struct reg_value ov5640_init_setting[] = {
54619a81c14SSteve Longerbeam 	{0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0},
547576f5d4bSLad Prabhakar 	{0x3103, 0x03, 0, 0}, {0x3630, 0x36, 0, 0},
54819a81c14SSteve Longerbeam 	{0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0},
54919a81c14SSteve Longerbeam 	{0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0},
55019a81c14SSteve Longerbeam 	{0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0},
55119a81c14SSteve Longerbeam 	{0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, {0x3906, 0x10, 0, 0},
55219a81c14SSteve Longerbeam 	{0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, {0x3600, 0x08, 0, 0},
55319a81c14SSteve Longerbeam 	{0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, {0x3620, 0x52, 0, 0},
55419a81c14SSteve Longerbeam 	{0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, {0x3a13, 0x43, 0, 0},
55519a81c14SSteve Longerbeam 	{0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3635, 0x13, 0, 0},
55619a81c14SSteve Longerbeam 	{0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, {0x3622, 0x01, 0, 0},
55719a81c14SSteve Longerbeam 	{0x3c01, 0xa4, 0, 0}, {0x3c04, 0x28, 0, 0}, {0x3c05, 0x98, 0, 0},
55819a81c14SSteve Longerbeam 	{0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0},
55919a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
56019a81c14SSteve Longerbeam 	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
5613145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
56219a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
56319a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
56419a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
56519a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
56619a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
56719a81c14SSteve Longerbeam 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0},
56819a81c14SSteve Longerbeam 	{0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0},
569aa4bb8b8SJacopo Mondi 	{0x302e, 0x08, 0, 0}, {0x4300, 0x3f, 0, 0},
5702b5c18f9SChen-Yu Tsai 	{0x501f, 0x00, 0, 0}, {0x4407, 0x04, 0, 0},
57119a81c14SSteve Longerbeam 	{0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
572aa4bb8b8SJacopo Mondi 	{0x4837, 0x0a, 0, 0}, {0x3824, 0x02, 0, 0},
57319a81c14SSteve Longerbeam 	{0x5000, 0xa7, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0},
57419a81c14SSteve Longerbeam 	{0x5181, 0xf2, 0, 0}, {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0},
57519a81c14SSteve Longerbeam 	{0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0},
57619a81c14SSteve Longerbeam 	{0x5187, 0x09, 0, 0}, {0x5188, 0x09, 0, 0}, {0x5189, 0x88, 0, 0},
57719a81c14SSteve Longerbeam 	{0x518a, 0x54, 0, 0}, {0x518b, 0xee, 0, 0}, {0x518c, 0xb2, 0, 0},
57819a81c14SSteve Longerbeam 	{0x518d, 0x50, 0, 0}, {0x518e, 0x34, 0, 0}, {0x518f, 0x6b, 0, 0},
57919a81c14SSteve Longerbeam 	{0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0},
58019a81c14SSteve Longerbeam 	{0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0},
58119a81c14SSteve Longerbeam 	{0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0},
58219a81c14SSteve Longerbeam 	{0x5199, 0x6c, 0, 0}, {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0},
58319a81c14SSteve Longerbeam 	{0x519c, 0x09, 0, 0}, {0x519d, 0x2b, 0, 0}, {0x519e, 0x38, 0, 0},
58419a81c14SSteve Longerbeam 	{0x5381, 0x1e, 0, 0}, {0x5382, 0x5b, 0, 0}, {0x5383, 0x08, 0, 0},
58519a81c14SSteve Longerbeam 	{0x5384, 0x0a, 0, 0}, {0x5385, 0x7e, 0, 0}, {0x5386, 0x88, 0, 0},
58619a81c14SSteve Longerbeam 	{0x5387, 0x7c, 0, 0}, {0x5388, 0x6c, 0, 0}, {0x5389, 0x10, 0, 0},
58719a81c14SSteve Longerbeam 	{0x538a, 0x01, 0, 0}, {0x538b, 0x98, 0, 0}, {0x5300, 0x08, 0, 0},
58819a81c14SSteve Longerbeam 	{0x5301, 0x30, 0, 0}, {0x5302, 0x10, 0, 0}, {0x5303, 0x00, 0, 0},
58919a81c14SSteve Longerbeam 	{0x5304, 0x08, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x08, 0, 0},
59019a81c14SSteve Longerbeam 	{0x5307, 0x16, 0, 0}, {0x5309, 0x08, 0, 0}, {0x530a, 0x30, 0, 0},
59119a81c14SSteve Longerbeam 	{0x530b, 0x04, 0, 0}, {0x530c, 0x06, 0, 0}, {0x5480, 0x01, 0, 0},
59219a81c14SSteve Longerbeam 	{0x5481, 0x08, 0, 0}, {0x5482, 0x14, 0, 0}, {0x5483, 0x28, 0, 0},
59319a81c14SSteve Longerbeam 	{0x5484, 0x51, 0, 0}, {0x5485, 0x65, 0, 0}, {0x5486, 0x71, 0, 0},
59419a81c14SSteve Longerbeam 	{0x5487, 0x7d, 0, 0}, {0x5488, 0x87, 0, 0}, {0x5489, 0x91, 0, 0},
59519a81c14SSteve Longerbeam 	{0x548a, 0x9a, 0, 0}, {0x548b, 0xaa, 0, 0}, {0x548c, 0xb8, 0, 0},
59619a81c14SSteve Longerbeam 	{0x548d, 0xcd, 0, 0}, {0x548e, 0xdd, 0, 0}, {0x548f, 0xea, 0, 0},
59719a81c14SSteve Longerbeam 	{0x5490, 0x1d, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5583, 0x40, 0, 0},
59819a81c14SSteve Longerbeam 	{0x5584, 0x10, 0, 0}, {0x5589, 0x10, 0, 0}, {0x558a, 0x00, 0, 0},
59919a81c14SSteve Longerbeam 	{0x558b, 0xf8, 0, 0}, {0x5800, 0x23, 0, 0}, {0x5801, 0x14, 0, 0},
60019a81c14SSteve Longerbeam 	{0x5802, 0x0f, 0, 0}, {0x5803, 0x0f, 0, 0}, {0x5804, 0x12, 0, 0},
60119a81c14SSteve Longerbeam 	{0x5805, 0x26, 0, 0}, {0x5806, 0x0c, 0, 0}, {0x5807, 0x08, 0, 0},
60219a81c14SSteve Longerbeam 	{0x5808, 0x05, 0, 0}, {0x5809, 0x05, 0, 0}, {0x580a, 0x08, 0, 0},
60319a81c14SSteve Longerbeam 	{0x580b, 0x0d, 0, 0}, {0x580c, 0x08, 0, 0}, {0x580d, 0x03, 0, 0},
60419a81c14SSteve Longerbeam 	{0x580e, 0x00, 0, 0}, {0x580f, 0x00, 0, 0}, {0x5810, 0x03, 0, 0},
60519a81c14SSteve Longerbeam 	{0x5811, 0x09, 0, 0}, {0x5812, 0x07, 0, 0}, {0x5813, 0x03, 0, 0},
60619a81c14SSteve Longerbeam 	{0x5814, 0x00, 0, 0}, {0x5815, 0x01, 0, 0}, {0x5816, 0x03, 0, 0},
60719a81c14SSteve Longerbeam 	{0x5817, 0x08, 0, 0}, {0x5818, 0x0d, 0, 0}, {0x5819, 0x08, 0, 0},
60819a81c14SSteve Longerbeam 	{0x581a, 0x05, 0, 0}, {0x581b, 0x06, 0, 0}, {0x581c, 0x08, 0, 0},
60919a81c14SSteve Longerbeam 	{0x581d, 0x0e, 0, 0}, {0x581e, 0x29, 0, 0}, {0x581f, 0x17, 0, 0},
61019a81c14SSteve Longerbeam 	{0x5820, 0x11, 0, 0}, {0x5821, 0x11, 0, 0}, {0x5822, 0x15, 0, 0},
61119a81c14SSteve Longerbeam 	{0x5823, 0x28, 0, 0}, {0x5824, 0x46, 0, 0}, {0x5825, 0x26, 0, 0},
61219a81c14SSteve Longerbeam 	{0x5826, 0x08, 0, 0}, {0x5827, 0x26, 0, 0}, {0x5828, 0x64, 0, 0},
61319a81c14SSteve Longerbeam 	{0x5829, 0x26, 0, 0}, {0x582a, 0x24, 0, 0}, {0x582b, 0x22, 0, 0},
61419a81c14SSteve Longerbeam 	{0x582c, 0x24, 0, 0}, {0x582d, 0x24, 0, 0}, {0x582e, 0x06, 0, 0},
61519a81c14SSteve Longerbeam 	{0x582f, 0x22, 0, 0}, {0x5830, 0x40, 0, 0}, {0x5831, 0x42, 0, 0},
61619a81c14SSteve Longerbeam 	{0x5832, 0x24, 0, 0}, {0x5833, 0x26, 0, 0}, {0x5834, 0x24, 0, 0},
61719a81c14SSteve Longerbeam 	{0x5835, 0x22, 0, 0}, {0x5836, 0x22, 0, 0}, {0x5837, 0x26, 0, 0},
61819a81c14SSteve Longerbeam 	{0x5838, 0x44, 0, 0}, {0x5839, 0x24, 0, 0}, {0x583a, 0x26, 0, 0},
61919a81c14SSteve Longerbeam 	{0x583b, 0x28, 0, 0}, {0x583c, 0x42, 0, 0}, {0x583d, 0xce, 0, 0},
62019a81c14SSteve Longerbeam 	{0x5025, 0x00, 0, 0}, {0x3a0f, 0x30, 0, 0}, {0x3a10, 0x28, 0, 0},
62119a81c14SSteve Longerbeam 	{0x3a1b, 0x30, 0, 0}, {0x3a1e, 0x26, 0, 0}, {0x3a11, 0x60, 0, 0},
62219a81c14SSteve Longerbeam 	{0x3a1f, 0x14, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3c00, 0x04, 0, 300},
62319a81c14SSteve Longerbeam };
62419a81c14SSteve Longerbeam 
625db15c195SJacopo Mondi static const struct reg_value ov5640_setting_low_res[] = {
626c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
62719a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
628ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
6293145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
63019a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
63119a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
63219a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
63319a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
63419a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
6352b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
636e15197bdSJacopo Mondi 	{0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0},
63719a81c14SSteve Longerbeam };
63819a81c14SSteve Longerbeam 
639086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_720P_1280_720[] = {
640c14d107eSMaxime Ripard 	{0x3c07, 0x07, 0, 0},
64119a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
642ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
6433145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
64419a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
64519a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0},
64619a81c14SSteve Longerbeam 	{0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0},
64719a81c14SSteve Longerbeam 	{0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0},
64819a81c14SSteve Longerbeam 	{0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0},
6492b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
65019a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
65119a81c14SSteve Longerbeam 	{0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0},
65219a81c14SSteve Longerbeam };
65319a81c14SSteve Longerbeam 
654086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_1080P_1920_1080[] = {
655c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
65619a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
657ce85705aSHugues Fruchet 	{0x3814, 0x11, 0, 0},
6583145efcdSJacopo Mondi 	{0x3815, 0x11, 0, 0},
65919a81c14SSteve Longerbeam 	{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
66019a81c14SSteve Longerbeam 	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
66119a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
66219a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
66319a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
6642b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0},
66519a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
666c14d107eSMaxime Ripard 	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0},
667c14d107eSMaxime Ripard 	{0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0},
66819a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
669476dec01SMaxime Ripard 	{0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0},
67019a81c14SSteve Longerbeam 	{0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0},
67119a81c14SSteve Longerbeam 	{0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0},
67219a81c14SSteve Longerbeam 	{0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0},
6732b5c18f9SChen-Yu Tsai 	{0x3a15, 0x60, 0, 0}, {0x4407, 0x04, 0, 0},
67419a81c14SSteve Longerbeam 	{0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0},
67592b9096cSBenoit Parrot 	{0x4005, 0x1a, 0, 0},
67619a81c14SSteve Longerbeam };
67719a81c14SSteve Longerbeam 
678086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_QSXGA_2592_1944[] = {
679c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
68019a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
681ce85705aSHugues Fruchet 	{0x3814, 0x11, 0, 0},
6823145efcdSJacopo Mondi 	{0x3815, 0x11, 0, 0},
68319a81c14SSteve Longerbeam 	{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
68419a81c14SSteve Longerbeam 	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
68519a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
68619a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
68719a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
6882b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0},
68919a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
69019a81c14SSteve Longerbeam 	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70},
69119a81c14SSteve Longerbeam };
69219a81c14SSteve Longerbeam 
6935113d5b3SJacopo Mondi static const struct ov5640_mode_info ov5640_mode_data[OV5640_NUM_MODES] = {
6948409d017SJacopo Mondi 	{
6958409d017SJacopo Mondi 		/* 160x120 */
6963145efcdSJacopo Mondi 		.id		= OV5640_MODE_QQVGA_160_120,
6973145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
6983145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
6995113d5b3SJacopo Mondi 		.width		= 160,
7005113d5b3SJacopo Mondi 		.height		= 120,
7015113d5b3SJacopo Mondi 		.dvp_timings = {
7023145efcdSJacopo Mondi 			.analog_crop = {
7033145efcdSJacopo Mondi 				.left	= 0,
7043145efcdSJacopo Mondi 				.top	= 4,
7053145efcdSJacopo Mondi 				.width	= 2624,
7063145efcdSJacopo Mondi 				.height	= 1944,
7073145efcdSJacopo Mondi 			},
7083145efcdSJacopo Mondi 			.crop = {
7093145efcdSJacopo Mondi 				.left	= 16,
7103145efcdSJacopo Mondi 				.top	= 6,
7113145efcdSJacopo Mondi 				.width	= 160,
7123145efcdSJacopo Mondi 				.height	= 120,
7133145efcdSJacopo Mondi 			},
7143145efcdSJacopo Mondi 			.htot		= 1896,
7153145efcdSJacopo Mondi 			.vblank_def	= 864,
7165113d5b3SJacopo Mondi 		},
7175113d5b3SJacopo Mondi 		.csi2_timings = {
7185113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
7195113d5b3SJacopo Mondi 			.analog_crop = {
7205113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
7215113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
7225113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
7235113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
7245113d5b3SJacopo Mondi 			},
7255113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
7265113d5b3SJacopo Mondi 			.crop = {
7275113d5b3SJacopo Mondi 				.left	= 2,
7285113d5b3SJacopo Mondi 				.top	= 4,
7295113d5b3SJacopo Mondi 				.width	= 160,
7305113d5b3SJacopo Mondi 				.height	= 120,
7315113d5b3SJacopo Mondi 			},
732961bed9fSJacopo Mondi 			.htot		= 1600,
733961bed9fSJacopo Mondi 			.vblank_def	= 878,
7345113d5b3SJacopo Mondi 		},
735db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
736db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
73719f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
73819f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
7398409d017SJacopo Mondi 	}, {
7408409d017SJacopo Mondi 		/* 176x144 */
7413145efcdSJacopo Mondi 		.id		= OV5640_MODE_QCIF_176_144,
7423145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
7433145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
7445113d5b3SJacopo Mondi 		.width		= 176,
7455113d5b3SJacopo Mondi 		.height		= 144,
7465113d5b3SJacopo Mondi 		.dvp_timings = {
7473145efcdSJacopo Mondi 			.analog_crop = {
7483145efcdSJacopo Mondi 				.left	= 0,
7493145efcdSJacopo Mondi 				.top	= 4,
7503145efcdSJacopo Mondi 				.width	= 2624,
7513145efcdSJacopo Mondi 				.height	= 1944,
7523145efcdSJacopo Mondi 			},
7533145efcdSJacopo Mondi 			.crop = {
7543145efcdSJacopo Mondi 				.left	= 16,
7553145efcdSJacopo Mondi 				.top	= 6,
7563145efcdSJacopo Mondi 				.width	= 176,
7573145efcdSJacopo Mondi 				.height	= 144,
7583145efcdSJacopo Mondi 			},
7593145efcdSJacopo Mondi 			.htot		= 1896,
7603145efcdSJacopo Mondi 			.vblank_def	= 840,
7615113d5b3SJacopo Mondi 		},
7625113d5b3SJacopo Mondi 		.csi2_timings = {
7635113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
7645113d5b3SJacopo Mondi 			.analog_crop = {
7655113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
7665113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
7675113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
7685113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
7695113d5b3SJacopo Mondi 			},
7705113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
7715113d5b3SJacopo Mondi 			.crop = {
7725113d5b3SJacopo Mondi 				.left	= 2,
7735113d5b3SJacopo Mondi 				.top	= 4,
7745113d5b3SJacopo Mondi 				.width	= 176,
7755113d5b3SJacopo Mondi 				.height	= 144,
7765113d5b3SJacopo Mondi 			},
777961bed9fSJacopo Mondi 			.htot		= 1600,
778961bed9fSJacopo Mondi 			.vblank_def	= 854,
7795113d5b3SJacopo Mondi 		},
780db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
781db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
78219f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
78319f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
7848409d017SJacopo Mondi 	}, {
7858409d017SJacopo Mondi 		/* 320x240 */
7863145efcdSJacopo Mondi 		.id		= OV5640_MODE_QVGA_320_240,
7873145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
7885113d5b3SJacopo Mondi 		.width		= 320,
7895113d5b3SJacopo Mondi 		.height		= 240,
7903145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
7915113d5b3SJacopo Mondi 		.dvp_timings = {
7923145efcdSJacopo Mondi 			.analog_crop = {
7933145efcdSJacopo Mondi 				.left	= 0,
7943145efcdSJacopo Mondi 				.top	= 4,
7953145efcdSJacopo Mondi 				.width	= 2624,
7963145efcdSJacopo Mondi 				.height	= 1944,
7973145efcdSJacopo Mondi 			},
7983145efcdSJacopo Mondi 			.crop = {
7993145efcdSJacopo Mondi 				.left	= 16,
8003145efcdSJacopo Mondi 				.top	= 6,
8013145efcdSJacopo Mondi 				.width	= 320,
8023145efcdSJacopo Mondi 				.height	= 240,
8033145efcdSJacopo Mondi 			},
8043145efcdSJacopo Mondi 			.htot		= 1896,
8053145efcdSJacopo Mondi 			.vblank_def	= 744,
8065113d5b3SJacopo Mondi 		},
8075113d5b3SJacopo Mondi 		.csi2_timings = {
8085113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
8095113d5b3SJacopo Mondi 			.analog_crop = {
8105113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
8115113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
8125113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
8135113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
8145113d5b3SJacopo Mondi 			},
8155113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
8165113d5b3SJacopo Mondi 			.crop = {
8175113d5b3SJacopo Mondi 				.left	= 2,
8185113d5b3SJacopo Mondi 				.top	= 4,
8195113d5b3SJacopo Mondi 				.width	= 320,
8205113d5b3SJacopo Mondi 				.height	= 240,
8215113d5b3SJacopo Mondi 			},
822961bed9fSJacopo Mondi 			.htot		= 1600,
823961bed9fSJacopo Mondi 			.vblank_def	= 760,
8245113d5b3SJacopo Mondi 		},
825db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
826db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
82719f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
82819f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
8298409d017SJacopo Mondi 	}, {
8308409d017SJacopo Mondi 		/* 640x480 */
8313145efcdSJacopo Mondi 		.id		= OV5640_MODE_VGA_640_480,
8323145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
8333145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
8345113d5b3SJacopo Mondi 		.width		= 640,
8355113d5b3SJacopo Mondi 		.height		= 480,
8365113d5b3SJacopo Mondi 		.dvp_timings = {
8373145efcdSJacopo Mondi 			.analog_crop = {
8383145efcdSJacopo Mondi 				.left	= 0,
8393145efcdSJacopo Mondi 				.top	= 4,
8403145efcdSJacopo Mondi 				.width	= 2624,
8413145efcdSJacopo Mondi 				.height	= 1944,
8423145efcdSJacopo Mondi 			},
8433145efcdSJacopo Mondi 			.crop = {
8443145efcdSJacopo Mondi 				.left	= 16,
8453145efcdSJacopo Mondi 				.top	= 6,
8463145efcdSJacopo Mondi 				.width	= 640,
8473145efcdSJacopo Mondi 				.height	= 480,
8483145efcdSJacopo Mondi 			},
8493145efcdSJacopo Mondi 			.htot		= 1896,
8503145efcdSJacopo Mondi 			.vblank_def	= 600,
8515113d5b3SJacopo Mondi 		},
8525113d5b3SJacopo Mondi 		.csi2_timings = {
8535113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
8545113d5b3SJacopo Mondi 			.analog_crop = {
8555113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
8565113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
8575113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
8585113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
8595113d5b3SJacopo Mondi 			},
8605113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
8615113d5b3SJacopo Mondi 			.crop = {
8625113d5b3SJacopo Mondi 				.left	= 2,
8635113d5b3SJacopo Mondi 				.top	= 4,
8645113d5b3SJacopo Mondi 				.width	= 640,
8655113d5b3SJacopo Mondi 				.height	= 480,
8665113d5b3SJacopo Mondi 			},
867961bed9fSJacopo Mondi 			.htot		= 1600,
868961bed9fSJacopo Mondi 			.vblank_def	= 520,
8695113d5b3SJacopo Mondi 		},
870db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
871db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
87219f2e3e6SHugues Fruchet 		.max_fps	= OV5640_60_FPS,
87319f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
8748409d017SJacopo Mondi 	}, {
8758409d017SJacopo Mondi 		/* 720x480 */
8763145efcdSJacopo Mondi 		.id		= OV5640_MODE_NTSC_720_480,
8773145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
8785113d5b3SJacopo Mondi 		.width		= 720,
8795113d5b3SJacopo Mondi 		.height		= 480,
8803145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
8815113d5b3SJacopo Mondi 		.dvp_timings = {
8823145efcdSJacopo Mondi 			.analog_crop = {
8833145efcdSJacopo Mondi 				.left	= 0,
8843145efcdSJacopo Mondi 				.top	= 4,
8853145efcdSJacopo Mondi 				.width	= 2624,
8863145efcdSJacopo Mondi 				.height	= 1944,
8873145efcdSJacopo Mondi 			},
8883145efcdSJacopo Mondi 			.crop = {
889e74ef55bSJacopo Mondi 				.left	= 56,
8903145efcdSJacopo Mondi 				.top	= 60,
8913145efcdSJacopo Mondi 				.width	= 720,
8923145efcdSJacopo Mondi 				.height	= 480,
8933145efcdSJacopo Mondi 			},
8943145efcdSJacopo Mondi 			.htot		= 1896,
8953145efcdSJacopo Mondi 			.vblank_def	= 504,
8965113d5b3SJacopo Mondi 		},
8975113d5b3SJacopo Mondi 		.csi2_timings = {
8985113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
8995113d5b3SJacopo Mondi 			.analog_crop = {
9005113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
9015113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
9025113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
9035113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
9045113d5b3SJacopo Mondi 			},
9055113d5b3SJacopo Mondi 			.crop = {
9065113d5b3SJacopo Mondi 				.left	= 56,
9075113d5b3SJacopo Mondi 				.top	= 60,
9085113d5b3SJacopo Mondi 				.width	= 720,
9095113d5b3SJacopo Mondi 				.height	= 480,
9105113d5b3SJacopo Mondi 			},
9115113d5b3SJacopo Mondi 			.htot		= 1896,
912961bed9fSJacopo Mondi 			.vblank_def	= 1206,
9135113d5b3SJacopo Mondi 		},
914db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
915db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
91619f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
91719f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
9188409d017SJacopo Mondi 	}, {
9198409d017SJacopo Mondi 		/* 720x576 */
9203145efcdSJacopo Mondi 		.id		= OV5640_MODE_PAL_720_576,
9213145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
9225113d5b3SJacopo Mondi 		.width		= 720,
9235113d5b3SJacopo Mondi 		.height		= 576,
9243145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
9255113d5b3SJacopo Mondi 		.dvp_timings = {
9263145efcdSJacopo Mondi 			.analog_crop = {
9273145efcdSJacopo Mondi 				.left	= 0,
9283145efcdSJacopo Mondi 				.top	= 4,
9293145efcdSJacopo Mondi 				.width	= 2624,
9303145efcdSJacopo Mondi 				.height	= 1944,
9313145efcdSJacopo Mondi 			},
9323145efcdSJacopo Mondi 			.crop = {
9333145efcdSJacopo Mondi 				.left	= 56,
9343145efcdSJacopo Mondi 				.top	= 6,
9353145efcdSJacopo Mondi 				.width	= 720,
9363145efcdSJacopo Mondi 				.height	= 576,
9373145efcdSJacopo Mondi 			},
9383145efcdSJacopo Mondi 			.htot		= 1896,
9393145efcdSJacopo Mondi 			.vblank_def	= 408,
9405113d5b3SJacopo Mondi 		},
9415113d5b3SJacopo Mondi 		.csi2_timings = {
9425113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
9435113d5b3SJacopo Mondi 			.analog_crop = {
9445113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
9455113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
9465113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
9475113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
9485113d5b3SJacopo Mondi 			},
9495113d5b3SJacopo Mondi 			.crop = {
9505113d5b3SJacopo Mondi 				.left	= 56,
9515113d5b3SJacopo Mondi 				.top	= 6,
9525113d5b3SJacopo Mondi 				.width	= 720,
9535113d5b3SJacopo Mondi 				.height	= 576,
9545113d5b3SJacopo Mondi 			},
9555113d5b3SJacopo Mondi 			.htot		= 1896,
956961bed9fSJacopo Mondi 			.vblank_def	= 1110,
9575113d5b3SJacopo Mondi 		},
958db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
959db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
96019f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
96119f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
9628409d017SJacopo Mondi 	}, {
9638409d017SJacopo Mondi 		/* 1024x768 */
9643145efcdSJacopo Mondi 		.id		= OV5640_MODE_XGA_1024_768,
9653145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
9663145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
9675113d5b3SJacopo Mondi 		.width		= 1024,
9685113d5b3SJacopo Mondi 		.height		= 768,
9695113d5b3SJacopo Mondi 		.dvp_timings = {
9703145efcdSJacopo Mondi 			.analog_crop = {
9713145efcdSJacopo Mondi 				.left	= 0,
9723145efcdSJacopo Mondi 				.top	= 4,
9733145efcdSJacopo Mondi 				.width	= 2624,
9743145efcdSJacopo Mondi 				.height	= 1944,
9753145efcdSJacopo Mondi 			},
9763145efcdSJacopo Mondi 			.crop = {
9773145efcdSJacopo Mondi 				.left	= 16,
9783145efcdSJacopo Mondi 				.top	= 6,
9793145efcdSJacopo Mondi 				.width	= 1024,
9803145efcdSJacopo Mondi 				.height	= 768,
9813145efcdSJacopo Mondi 			},
9823145efcdSJacopo Mondi 			.htot		= 1896,
9833145efcdSJacopo Mondi 			.vblank_def	= 312,
9845113d5b3SJacopo Mondi 		},
9855113d5b3SJacopo Mondi 		.csi2_timings = {
9865113d5b3SJacopo Mondi 			.analog_crop = {
9875113d5b3SJacopo Mondi 				.left	= 0,
9885113d5b3SJacopo Mondi 				.top	= 4,
9895113d5b3SJacopo Mondi 				.width	= OV5640_NATIVE_WIDTH,
9905113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
9915113d5b3SJacopo Mondi 			},
9925113d5b3SJacopo Mondi 			.crop = {
9935113d5b3SJacopo Mondi 				.left	= 16,
9945113d5b3SJacopo Mondi 				.top	= 6,
9955113d5b3SJacopo Mondi 				.width	= 1024,
9965113d5b3SJacopo Mondi 				.height	= 768,
9975113d5b3SJacopo Mondi 			},
9985113d5b3SJacopo Mondi 			.htot		= 1896,
999961bed9fSJacopo Mondi 			.vblank_def	= 918,
10005113d5b3SJacopo Mondi 		},
1001db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
1002db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
100319f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
100419f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
10058409d017SJacopo Mondi 	}, {
10068409d017SJacopo Mondi 		/* 1280x720 */
10073145efcdSJacopo Mondi 		.id		= OV5640_MODE_720P_1280_720,
10083145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
10093145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_124M,
10105113d5b3SJacopo Mondi 		.width		= 1280,
10115113d5b3SJacopo Mondi 		.height		= 720,
10125113d5b3SJacopo Mondi 		.dvp_timings = {
10133145efcdSJacopo Mondi 			.analog_crop = {
10143145efcdSJacopo Mondi 				.left	= 0,
10153145efcdSJacopo Mondi 				.top	= 250,
10163145efcdSJacopo Mondi 				.width	= 2624,
10173145efcdSJacopo Mondi 				.height	= 1456,
10183145efcdSJacopo Mondi 			},
10193145efcdSJacopo Mondi 			.crop = {
10203145efcdSJacopo Mondi 				.left	= 16,
10213145efcdSJacopo Mondi 				.top	= 4,
10223145efcdSJacopo Mondi 				.width	= 1280,
10233145efcdSJacopo Mondi 				.height	= 720,
10243145efcdSJacopo Mondi 			},
10253145efcdSJacopo Mondi 			.htot		= 1892,
10263145efcdSJacopo Mondi 			.vblank_def	= 20,
10275113d5b3SJacopo Mondi 		},
10285113d5b3SJacopo Mondi 		.csi2_timings = {
10295113d5b3SJacopo Mondi 			.analog_crop = {
10305113d5b3SJacopo Mondi 				.left	= 0,
10315113d5b3SJacopo Mondi 				.top	= 250,
10325113d5b3SJacopo Mondi 				.width	= 2624,
10335113d5b3SJacopo Mondi 				.height	= 1456,
10345113d5b3SJacopo Mondi 			},
10355113d5b3SJacopo Mondi 			.crop = {
10365113d5b3SJacopo Mondi 				.left	= 16,
10375113d5b3SJacopo Mondi 				.top	= 4,
10385113d5b3SJacopo Mondi 				.width	= 1280,
10395113d5b3SJacopo Mondi 				.height	= 720,
10405113d5b3SJacopo Mondi 			},
1041961bed9fSJacopo Mondi 			.htot		= 1600,
1042961bed9fSJacopo Mondi 			.vblank_def	= 560,
10435113d5b3SJacopo Mondi 		},
10443145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_720P_1280_720,
10453145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_720P_1280_720),
104619f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
104719f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
10488409d017SJacopo Mondi 	}, {
10498409d017SJacopo Mondi 		/* 1920x1080 */
10503145efcdSJacopo Mondi 		.id		= OV5640_MODE_1080P_1920_1080,
10513145efcdSJacopo Mondi 		.dn_mode	= SCALING,
10523145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_148M,
10535113d5b3SJacopo Mondi 		.width		= 1920,
10545113d5b3SJacopo Mondi 		.height		= 1080,
10555113d5b3SJacopo Mondi 		.dvp_timings = {
10563145efcdSJacopo Mondi 			.analog_crop = {
10573145efcdSJacopo Mondi 				.left	= 336,
10583145efcdSJacopo Mondi 				.top	= 434,
10593145efcdSJacopo Mondi 				.width	= 1952,
10603145efcdSJacopo Mondi 				.height	= 1088,
10613145efcdSJacopo Mondi 			},
10623145efcdSJacopo Mondi 			.crop = {
10633145efcdSJacopo Mondi 				.left	= 16,
10643145efcdSJacopo Mondi 				.top	= 4,
10653145efcdSJacopo Mondi 				.width	= 1920,
10663145efcdSJacopo Mondi 				.height	= 1080,
10673145efcdSJacopo Mondi 			},
10683145efcdSJacopo Mondi 			.htot		= 2500,
10693145efcdSJacopo Mondi 			.vblank_def	= 40,
10705113d5b3SJacopo Mondi 		},
10715113d5b3SJacopo Mondi 		.csi2_timings = {
10725113d5b3SJacopo Mondi 			/* Crop the full valid pixel array in the center. */
10735113d5b3SJacopo Mondi 			.analog_crop = {
10745113d5b3SJacopo Mondi 				.left	= 336,
10755113d5b3SJacopo Mondi 				.top	= 434,
10765113d5b3SJacopo Mondi 				.width	= 1952,
10775113d5b3SJacopo Mondi 				.height	= 1088,
10785113d5b3SJacopo Mondi 			},
10795113d5b3SJacopo Mondi 			/* Maintain a larger processing margins. */
10805113d5b3SJacopo Mondi 			.crop = {
10815113d5b3SJacopo Mondi 				.left	= 16,
10825113d5b3SJacopo Mondi 				.top	= 4,
10835113d5b3SJacopo Mondi 				.width	= 1920,
10845113d5b3SJacopo Mondi 				.height	= 1080,
10855113d5b3SJacopo Mondi 			},
1086961bed9fSJacopo Mondi 			.htot		= 2234,
1087961bed9fSJacopo Mondi 			.vblank_def	= 24,
10885113d5b3SJacopo Mondi 		},
10893145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_1080P_1920_1080,
10903145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_1080P_1920_1080),
109119f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
109219f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
10938409d017SJacopo Mondi 	}, {
10948409d017SJacopo Mondi 		/* 2592x1944 */
10953145efcdSJacopo Mondi 		.id		= OV5640_MODE_QSXGA_2592_1944,
10963145efcdSJacopo Mondi 		.dn_mode	= SCALING,
10973145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_168M,
10985113d5b3SJacopo Mondi 		.width		= OV5640_PIXEL_ARRAY_WIDTH,
10995113d5b3SJacopo Mondi 		.height		= OV5640_PIXEL_ARRAY_HEIGHT,
11005113d5b3SJacopo Mondi 		.dvp_timings = {
11013145efcdSJacopo Mondi 			.analog_crop = {
11023145efcdSJacopo Mondi 				.left	= 0,
11033145efcdSJacopo Mondi 				.top	= 0,
11043145efcdSJacopo Mondi 				.width	= 2624,
11053145efcdSJacopo Mondi 				.height	= 1952,
11063145efcdSJacopo Mondi 			},
11073145efcdSJacopo Mondi 			.crop = {
11083145efcdSJacopo Mondi 				.left	= 16,
11093145efcdSJacopo Mondi 				.top	= 4,
11103145efcdSJacopo Mondi 				.width	= 2592,
11113145efcdSJacopo Mondi 				.height	= 1944,
11123145efcdSJacopo Mondi 			},
11133145efcdSJacopo Mondi 			.htot		= 2844,
11143145efcdSJacopo Mondi 			.vblank_def	= 24,
11155113d5b3SJacopo Mondi 		},
11165113d5b3SJacopo Mondi 		.csi2_timings = {
11175113d5b3SJacopo Mondi 			/* Give more processing margin to full resolution. */
11185113d5b3SJacopo Mondi 			.analog_crop = {
11195113d5b3SJacopo Mondi 				.left	= 0,
11205113d5b3SJacopo Mondi 				.top	= 0,
11215113d5b3SJacopo Mondi 				.width	= OV5640_NATIVE_WIDTH,
11225113d5b3SJacopo Mondi 				.height	= 1952,
11235113d5b3SJacopo Mondi 			},
11245113d5b3SJacopo Mondi 			.crop = {
11255113d5b3SJacopo Mondi 				.left	= 16,
11265113d5b3SJacopo Mondi 				.top	= 4,
11275113d5b3SJacopo Mondi 				.width	= 2592,
11285113d5b3SJacopo Mondi 				.height	= 1944,
11295113d5b3SJacopo Mondi 			},
11305113d5b3SJacopo Mondi 			.htot		= 2844,
11315113d5b3SJacopo Mondi 			.vblank_def	= 24,
11325113d5b3SJacopo Mondi 		},
11333145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_QSXGA_2592_1944,
11343145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_QSXGA_2592_1944),
113519f2e3e6SHugues Fruchet 		.max_fps	= OV5640_15_FPS,
113619f2e3e6SHugues Fruchet 		.def_fps	= OV5640_15_FPS
11378409d017SJacopo Mondi 	},
113819a81c14SSteve Longerbeam };
113919a81c14SSteve Longerbeam 
11402de6bb97SJacopo Mondi static const struct ov5640_timings *
11412de6bb97SJacopo Mondi ov5640_timings(const struct ov5640_dev *sensor,
11422de6bb97SJacopo Mondi 	       const struct ov5640_mode_info *mode)
11432de6bb97SJacopo Mondi {
11442de6bb97SJacopo Mondi 	if (ov5640_is_csi2(sensor))
11452de6bb97SJacopo Mondi 		return &mode->csi2_timings;
11462de6bb97SJacopo Mondi 
11472de6bb97SJacopo Mondi 	return &mode->dvp_timings;
11482de6bb97SJacopo Mondi }
11492de6bb97SJacopo Mondi 
115019a81c14SSteve Longerbeam static int ov5640_init_slave_id(struct ov5640_dev *sensor)
115119a81c14SSteve Longerbeam {
115219a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
115319a81c14SSteve Longerbeam 	struct i2c_msg msg;
115419a81c14SSteve Longerbeam 	u8 buf[3];
115519a81c14SSteve Longerbeam 	int ret;
115619a81c14SSteve Longerbeam 
115719a81c14SSteve Longerbeam 	if (client->addr == OV5640_DEFAULT_SLAVE_ID)
115819a81c14SSteve Longerbeam 		return 0;
115919a81c14SSteve Longerbeam 
116019a81c14SSteve Longerbeam 	buf[0] = OV5640_REG_SLAVE_ID >> 8;
116119a81c14SSteve Longerbeam 	buf[1] = OV5640_REG_SLAVE_ID & 0xff;
116219a81c14SSteve Longerbeam 	buf[2] = client->addr << 1;
116319a81c14SSteve Longerbeam 
116419a81c14SSteve Longerbeam 	msg.addr = OV5640_DEFAULT_SLAVE_ID;
116519a81c14SSteve Longerbeam 	msg.flags = 0;
116619a81c14SSteve Longerbeam 	msg.buf = buf;
116719a81c14SSteve Longerbeam 	msg.len = sizeof(buf);
116819a81c14SSteve Longerbeam 
116919a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, &msg, 1);
117019a81c14SSteve Longerbeam 	if (ret < 0) {
117119a81c14SSteve Longerbeam 		dev_err(&client->dev, "%s: failed with %d\n", __func__, ret);
117219a81c14SSteve Longerbeam 		return ret;
117319a81c14SSteve Longerbeam 	}
117419a81c14SSteve Longerbeam 
117519a81c14SSteve Longerbeam 	return 0;
117619a81c14SSteve Longerbeam }
117719a81c14SSteve Longerbeam 
117819a81c14SSteve Longerbeam static int ov5640_write_reg(struct ov5640_dev *sensor, u16 reg, u8 val)
117919a81c14SSteve Longerbeam {
118019a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
118119a81c14SSteve Longerbeam 	struct i2c_msg msg;
118219a81c14SSteve Longerbeam 	u8 buf[3];
118319a81c14SSteve Longerbeam 	int ret;
118419a81c14SSteve Longerbeam 
118519a81c14SSteve Longerbeam 	buf[0] = reg >> 8;
118619a81c14SSteve Longerbeam 	buf[1] = reg & 0xff;
118719a81c14SSteve Longerbeam 	buf[2] = val;
118819a81c14SSteve Longerbeam 
118919a81c14SSteve Longerbeam 	msg.addr = client->addr;
119019a81c14SSteve Longerbeam 	msg.flags = client->flags;
119119a81c14SSteve Longerbeam 	msg.buf = buf;
119219a81c14SSteve Longerbeam 	msg.len = sizeof(buf);
119319a81c14SSteve Longerbeam 
119419a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, &msg, 1);
119519a81c14SSteve Longerbeam 	if (ret < 0) {
11963924c623SHugues Fruchet 		dev_err(&client->dev, "%s: error: reg=%x, val=%x\n",
119719a81c14SSteve Longerbeam 			__func__, reg, val);
119819a81c14SSteve Longerbeam 		return ret;
119919a81c14SSteve Longerbeam 	}
120019a81c14SSteve Longerbeam 
120119a81c14SSteve Longerbeam 	return 0;
120219a81c14SSteve Longerbeam }
120319a81c14SSteve Longerbeam 
120419a81c14SSteve Longerbeam static int ov5640_read_reg(struct ov5640_dev *sensor, u16 reg, u8 *val)
120519a81c14SSteve Longerbeam {
120619a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
120719a81c14SSteve Longerbeam 	struct i2c_msg msg[2];
120819a81c14SSteve Longerbeam 	u8 buf[2];
120919a81c14SSteve Longerbeam 	int ret;
121019a81c14SSteve Longerbeam 
121119a81c14SSteve Longerbeam 	buf[0] = reg >> 8;
121219a81c14SSteve Longerbeam 	buf[1] = reg & 0xff;
121319a81c14SSteve Longerbeam 
121419a81c14SSteve Longerbeam 	msg[0].addr = client->addr;
121519a81c14SSteve Longerbeam 	msg[0].flags = client->flags;
121619a81c14SSteve Longerbeam 	msg[0].buf = buf;
121719a81c14SSteve Longerbeam 	msg[0].len = sizeof(buf);
121819a81c14SSteve Longerbeam 
121919a81c14SSteve Longerbeam 	msg[1].addr = client->addr;
122019a81c14SSteve Longerbeam 	msg[1].flags = client->flags | I2C_M_RD;
122119a81c14SSteve Longerbeam 	msg[1].buf = buf;
122219a81c14SSteve Longerbeam 	msg[1].len = 1;
122319a81c14SSteve Longerbeam 
122419a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, msg, 2);
12253924c623SHugues Fruchet 	if (ret < 0) {
12263924c623SHugues Fruchet 		dev_err(&client->dev, "%s: error: reg=%x\n",
12273924c623SHugues Fruchet 			__func__, reg);
122819a81c14SSteve Longerbeam 		return ret;
12293924c623SHugues Fruchet 	}
123019a81c14SSteve Longerbeam 
123119a81c14SSteve Longerbeam 	*val = buf[0];
123219a81c14SSteve Longerbeam 	return 0;
123319a81c14SSteve Longerbeam }
123419a81c14SSteve Longerbeam 
123519a81c14SSteve Longerbeam static int ov5640_read_reg16(struct ov5640_dev *sensor, u16 reg, u16 *val)
123619a81c14SSteve Longerbeam {
123719a81c14SSteve Longerbeam 	u8 hi, lo;
123819a81c14SSteve Longerbeam 	int ret;
123919a81c14SSteve Longerbeam 
124019a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg, &hi);
124119a81c14SSteve Longerbeam 	if (ret)
124219a81c14SSteve Longerbeam 		return ret;
124319a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg + 1, &lo);
124419a81c14SSteve Longerbeam 	if (ret)
124519a81c14SSteve Longerbeam 		return ret;
124619a81c14SSteve Longerbeam 
124719a81c14SSteve Longerbeam 	*val = ((u16)hi << 8) | (u16)lo;
124819a81c14SSteve Longerbeam 	return 0;
124919a81c14SSteve Longerbeam }
125019a81c14SSteve Longerbeam 
125119a81c14SSteve Longerbeam static int ov5640_write_reg16(struct ov5640_dev *sensor, u16 reg, u16 val)
125219a81c14SSteve Longerbeam {
125319a81c14SSteve Longerbeam 	int ret;
125419a81c14SSteve Longerbeam 
125519a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, reg, val >> 8);
125619a81c14SSteve Longerbeam 	if (ret)
125719a81c14SSteve Longerbeam 		return ret;
125819a81c14SSteve Longerbeam 
125919a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, reg + 1, val & 0xff);
126019a81c14SSteve Longerbeam }
126119a81c14SSteve Longerbeam 
126219a81c14SSteve Longerbeam static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg,
126319a81c14SSteve Longerbeam 			  u8 mask, u8 val)
126419a81c14SSteve Longerbeam {
126519a81c14SSteve Longerbeam 	u8 readval;
126619a81c14SSteve Longerbeam 	int ret;
126719a81c14SSteve Longerbeam 
126819a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg, &readval);
126919a81c14SSteve Longerbeam 	if (ret)
127019a81c14SSteve Longerbeam 		return ret;
127119a81c14SSteve Longerbeam 
127219a81c14SSteve Longerbeam 	readval &= ~mask;
127319a81c14SSteve Longerbeam 	val &= mask;
127419a81c14SSteve Longerbeam 	val |= readval;
127519a81c14SSteve Longerbeam 
127619a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, reg, val);
127719a81c14SSteve Longerbeam }
127819a81c14SSteve Longerbeam 
1279aa288248SMaxime Ripard /*
1280aa288248SMaxime Ripard  * After trying the various combinations, reading various
1281f8a7647dSMauro Carvalho Chehab  * documentations spread around the net, and from the various
1282aa288248SMaxime Ripard  * feedback, the clock tree is probably as follows:
1283aa288248SMaxime Ripard  *
1284aa288248SMaxime Ripard  *   +--------------+
1285aa288248SMaxime Ripard  *   |  Ext. Clock  |
1286aa288248SMaxime Ripard  *   +-+------------+
1287aa288248SMaxime Ripard  *     |  +----------+
1288aa288248SMaxime Ripard  *     +->|   PLL1   | - reg 0x3036, for the multiplier
1289aa288248SMaxime Ripard  *        +-+--------+ - reg 0x3037, bits 0-3 for the pre-divider
1290aa288248SMaxime Ripard  *          |  +--------------+
1291aa288248SMaxime Ripard  *          +->| System Clock |  - reg 0x3035, bits 4-7
1292aa288248SMaxime Ripard  *             +-+------------+
1293aa288248SMaxime Ripard  *               |  +--------------+
1294aa288248SMaxime Ripard  *               +->| MIPI Divider | - reg 0x3035, bits 0-3
1295aa288248SMaxime Ripard  *               |  +-+------------+
1296aa288248SMaxime Ripard  *               |    +----------------> MIPI SCLK
1297aa288248SMaxime Ripard  *               |    +  +-----+
1298aa288248SMaxime Ripard  *               |    +->| / 2 |-------> MIPI BIT CLK
1299aa288248SMaxime Ripard  *               |       +-----+
1300aa288248SMaxime Ripard  *               |  +--------------+
1301aa288248SMaxime Ripard  *               +->| PLL Root Div | - reg 0x3037, bit 4
1302aa288248SMaxime Ripard  *                  +-+------------+
1303aa288248SMaxime Ripard  *                    |  +---------+
13044c85f628SPaul Kocialkowski  *                    +->| Bit Div | - reg 0x3034, bits 0-3
1305aa288248SMaxime Ripard  *                       +-+-------+
1306aa288248SMaxime Ripard  *                         |  +-------------+
1307aa288248SMaxime Ripard  *                         +->| SCLK Div    | - reg 0x3108, bits 0-1
1308aa288248SMaxime Ripard  *                         |  +-+-----------+
1309aa288248SMaxime Ripard  *                         |    +---------------> SCLK
1310aa288248SMaxime Ripard  *                         |  +-------------+
1311aa288248SMaxime Ripard  *                         +->| SCLK 2X Div | - reg 0x3108, bits 2-3
1312aa288248SMaxime Ripard  *                         |  +-+-----------+
1313aa288248SMaxime Ripard  *                         |    +---------------> SCLK 2X
1314aa288248SMaxime Ripard  *                         |  +-------------+
1315aa288248SMaxime Ripard  *                         +->| PCLK Div    | - reg 0x3108, bits 4-5
1316aa288248SMaxime Ripard  *                            ++------------+
1317aa288248SMaxime Ripard  *                             +  +-----------+
1318aa288248SMaxime Ripard  *                             +->|   P_DIV   | - reg 0x3035, bits 0-3
1319aa288248SMaxime Ripard  *                                +-----+-----+
1320aa288248SMaxime Ripard  *                                       +------------> PCLK
1321aa288248SMaxime Ripard  *
13226c957ed7SJacopo Mondi  * There seems to be also constraints:
1323aa288248SMaxime Ripard  *  - the PLL pre-divider output rate should be in the 4-27MHz range
1324aa288248SMaxime Ripard  *  - the PLL multiplier output rate should be in the 500-1000MHz range
1325aa288248SMaxime Ripard  *  - PCLK >= SCLK * 2 in YUV, >= SCLK in Raw or JPEG
1326aa288248SMaxime Ripard  */
1327aa288248SMaxime Ripard 
1328aa288248SMaxime Ripard /*
1329aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1330aa288248SMaxime Ripard  * set to 3 in the vendor kernels.
1331aa288248SMaxime Ripard  */
1332aa288248SMaxime Ripard #define OV5640_PLL_PREDIV	3
1333aa288248SMaxime Ripard 
1334aa288248SMaxime Ripard #define OV5640_PLL_MULT_MIN	4
1335aa288248SMaxime Ripard #define OV5640_PLL_MULT_MAX	252
1336aa288248SMaxime Ripard 
1337aa288248SMaxime Ripard /*
1338aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 16, but the value is
1339aa288248SMaxime Ripard  * always set to either 1 or 2 in the vendor kernels.
1340aa288248SMaxime Ripard  */
1341aa288248SMaxime Ripard #define OV5640_SYSDIV_MIN	1
1342aa288248SMaxime Ripard #define OV5640_SYSDIV_MAX	16
1343aa288248SMaxime Ripard 
1344aa288248SMaxime Ripard /*
1345aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 2, but the value is always
1346aa288248SMaxime Ripard  * set to 2 in the vendor kernels.
1347aa288248SMaxime Ripard  */
1348aa288248SMaxime Ripard #define OV5640_PLL_ROOT_DIV			2
1349aa288248SMaxime Ripard #define OV5640_PLL_CTRL3_PLL_ROOT_DIV_2		BIT(4)
1350aa288248SMaxime Ripard 
1351aa288248SMaxime Ripard /*
1352aa288248SMaxime Ripard  * We only supports 8-bit formats at the moment
1353aa288248SMaxime Ripard  */
1354aa288248SMaxime Ripard #define OV5640_BIT_DIV				2
1355aa288248SMaxime Ripard #define OV5640_PLL_CTRL0_MIPI_MODE_8BIT		0x08
1356aa288248SMaxime Ripard 
1357aa288248SMaxime Ripard /*
1358aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1359aa288248SMaxime Ripard  * set to 2 in the vendor kernels.
1360aa288248SMaxime Ripard  */
1361aa288248SMaxime Ripard #define OV5640_SCLK_ROOT_DIV	2
1362aa288248SMaxime Ripard 
1363aa288248SMaxime Ripard /*
1364aa288248SMaxime Ripard  * This is hardcoded so that the consistency is maintained between SCLK and
1365aa288248SMaxime Ripard  * SCLK 2x.
1366aa288248SMaxime Ripard  */
1367aa288248SMaxime Ripard #define OV5640_SCLK2X_ROOT_DIV (OV5640_SCLK_ROOT_DIV / 2)
1368aa288248SMaxime Ripard 
1369aa288248SMaxime Ripard /*
1370aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1371aa288248SMaxime Ripard  * set to 1 in the vendor kernels.
1372aa288248SMaxime Ripard  */
1373aa288248SMaxime Ripard #define OV5640_PCLK_ROOT_DIV			1
1374aa288248SMaxime Ripard #define OV5640_PLL_SYS_ROOT_DIVIDER_BYPASS	0x00
1375aa288248SMaxime Ripard 
1376aa288248SMaxime Ripard static unsigned long ov5640_compute_sys_clk(struct ov5640_dev *sensor,
1377aa288248SMaxime Ripard 					    u8 pll_prediv, u8 pll_mult,
1378aa288248SMaxime Ripard 					    u8 sysdiv)
1379aa288248SMaxime Ripard {
1380aa288248SMaxime Ripard 	unsigned long sysclk = sensor->xclk_freq / pll_prediv * pll_mult;
1381aa288248SMaxime Ripard 
1382aa288248SMaxime Ripard 	/* PLL1 output cannot exceed 1GHz. */
1383aa288248SMaxime Ripard 	if (sysclk / 1000000 > 1000)
1384aa288248SMaxime Ripard 		return 0;
1385aa288248SMaxime Ripard 
1386aa288248SMaxime Ripard 	return sysclk / sysdiv;
1387aa288248SMaxime Ripard }
1388aa288248SMaxime Ripard 
1389aa288248SMaxime Ripard static unsigned long ov5640_calc_sys_clk(struct ov5640_dev *sensor,
1390aa288248SMaxime Ripard 					 unsigned long rate,
1391aa288248SMaxime Ripard 					 u8 *pll_prediv, u8 *pll_mult,
1392aa288248SMaxime Ripard 					 u8 *sysdiv)
1393aa288248SMaxime Ripard {
1394aa288248SMaxime Ripard 	unsigned long best = ~0;
1395aa288248SMaxime Ripard 	u8 best_sysdiv = 1, best_mult = 1;
1396aa288248SMaxime Ripard 	u8 _sysdiv, _pll_mult;
1397aa288248SMaxime Ripard 
1398aa288248SMaxime Ripard 	for (_sysdiv = OV5640_SYSDIV_MIN;
1399aa288248SMaxime Ripard 	     _sysdiv <= OV5640_SYSDIV_MAX;
1400aa288248SMaxime Ripard 	     _sysdiv++) {
1401aa288248SMaxime Ripard 		for (_pll_mult = OV5640_PLL_MULT_MIN;
1402aa288248SMaxime Ripard 		     _pll_mult <= OV5640_PLL_MULT_MAX;
1403aa288248SMaxime Ripard 		     _pll_mult++) {
1404aa288248SMaxime Ripard 			unsigned long _rate;
1405aa288248SMaxime Ripard 
1406aa288248SMaxime Ripard 			/*
1407aa288248SMaxime Ripard 			 * The PLL multiplier cannot be odd if above
1408aa288248SMaxime Ripard 			 * 127.
1409aa288248SMaxime Ripard 			 */
1410aa288248SMaxime Ripard 			if (_pll_mult > 127 && (_pll_mult % 2))
1411aa288248SMaxime Ripard 				continue;
1412aa288248SMaxime Ripard 
1413aa288248SMaxime Ripard 			_rate = ov5640_compute_sys_clk(sensor,
1414aa288248SMaxime Ripard 						       OV5640_PLL_PREDIV,
1415aa288248SMaxime Ripard 						       _pll_mult, _sysdiv);
1416aa288248SMaxime Ripard 
1417aa288248SMaxime Ripard 			/*
1418aa288248SMaxime Ripard 			 * We have reached the maximum allowed PLL1 output,
1419aa288248SMaxime Ripard 			 * increase sysdiv.
1420aa288248SMaxime Ripard 			 */
14212e3df204SAdam Ford 			if (!_rate)
1422aa288248SMaxime Ripard 				break;
1423aa288248SMaxime Ripard 
1424aa288248SMaxime Ripard 			/*
1425aa288248SMaxime Ripard 			 * Prefer rates above the expected clock rate than
1426aa288248SMaxime Ripard 			 * below, even if that means being less precise.
1427aa288248SMaxime Ripard 			 */
1428aa288248SMaxime Ripard 			if (_rate < rate)
1429aa288248SMaxime Ripard 				continue;
1430aa288248SMaxime Ripard 
1431aa288248SMaxime Ripard 			if (abs(rate - _rate) < abs(rate - best)) {
1432aa288248SMaxime Ripard 				best = _rate;
1433aa288248SMaxime Ripard 				best_sysdiv = _sysdiv;
1434aa288248SMaxime Ripard 				best_mult = _pll_mult;
1435aa288248SMaxime Ripard 			}
1436aa288248SMaxime Ripard 
1437aa288248SMaxime Ripard 			if (_rate == rate)
1438aa288248SMaxime Ripard 				goto out;
1439aa288248SMaxime Ripard 		}
1440aa288248SMaxime Ripard 	}
1441aa288248SMaxime Ripard 
1442aa288248SMaxime Ripard out:
1443aa288248SMaxime Ripard 	*sysdiv = best_sysdiv;
1444aa288248SMaxime Ripard 	*pll_prediv = OV5640_PLL_PREDIV;
1445aa288248SMaxime Ripard 	*pll_mult = best_mult;
1446aa288248SMaxime Ripard 
1447aa288248SMaxime Ripard 	return best;
1448aa288248SMaxime Ripard }
1449aa288248SMaxime Ripard 
1450aa288248SMaxime Ripard /*
1451aa288248SMaxime Ripard  * ov5640_set_mipi_pclk() - Calculate the clock tree configuration values
1452aa288248SMaxime Ripard  *			    for the MIPI CSI-2 output.
1453aa288248SMaxime Ripard  */
14546c957ed7SJacopo Mondi static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor)
1455aa288248SMaxime Ripard {
14566c957ed7SJacopo Mondi 	u8 bit_div, mipi_div, pclk_div, sclk_div, sclk2x_div, root_div;
1457aa288248SMaxime Ripard 	u8 prediv, mult, sysdiv;
14586c957ed7SJacopo Mondi 	unsigned long link_freq;
14596c957ed7SJacopo Mondi 	unsigned long sysclk;
14606c957ed7SJacopo Mondi 	u8 pclk_period;
14616c957ed7SJacopo Mondi 	u32 sample_rate;
14626c957ed7SJacopo Mondi 	u32 num_lanes;
1463aa288248SMaxime Ripard 	int ret;
1464aa288248SMaxime Ripard 
14656c957ed7SJacopo Mondi 	/* Use the link freq computed at ov5640_update_pixel_rate() time. */
14666c957ed7SJacopo Mondi 	link_freq = sensor->current_link_freq;
14676c957ed7SJacopo Mondi 
1468aa288248SMaxime Ripard 	/*
14696c957ed7SJacopo Mondi 	 * - mipi_div - Additional divider for the MIPI lane clock.
14706c957ed7SJacopo Mondi 	 *
14716c957ed7SJacopo Mondi 	 * Higher link frequencies would make sysclk > 1GHz.
14726c957ed7SJacopo Mondi 	 * Keep the sysclk low and do not divide in the MIPI domain.
1473aa288248SMaxime Ripard 	 */
14746c957ed7SJacopo Mondi 	if (link_freq > OV5640_LINK_RATE_MAX)
14756c957ed7SJacopo Mondi 		mipi_div = 1;
1476aa288248SMaxime Ripard 	else
14776c957ed7SJacopo Mondi 		mipi_div = 2;
1478aa288248SMaxime Ripard 
14796c957ed7SJacopo Mondi 	sysclk = link_freq * mipi_div;
14806c957ed7SJacopo Mondi 	ov5640_calc_sys_clk(sensor, sysclk, &prediv, &mult, &sysdiv);
1481aa288248SMaxime Ripard 
14826c957ed7SJacopo Mondi 	/*
14836c957ed7SJacopo Mondi 	 * Adjust PLL parameters to maintain the MIPI_SCLK-to-PCLK ratio.
14846c957ed7SJacopo Mondi 	 *
14856c957ed7SJacopo Mondi 	 * - root_div = 2 (fixed)
14866c957ed7SJacopo Mondi 	 * - bit_div : MIPI 8-bit = 2; MIPI 10-bit = 2.5
14876c957ed7SJacopo Mondi 	 * - pclk_div = 1 (fixed)
14886c957ed7SJacopo Mondi 	 * - p_div  = (2 lanes ? mipi_div : 2 * mipi_div)
14896c957ed7SJacopo Mondi 	 *
14906c957ed7SJacopo Mondi 	 * This results in the following MIPI_SCLK depending on the number
14916c957ed7SJacopo Mondi 	 * of lanes:
14926c957ed7SJacopo Mondi 	 *
14936c957ed7SJacopo Mondi 	 * - 2 lanes: MIPI_SCLK = (4 or 5) * PCLK
14946c957ed7SJacopo Mondi 	 * - 1 lanes: MIPI_SCLK = (8 or 10) * PCLK
14956c957ed7SJacopo Mondi 	 */
14966c957ed7SJacopo Mondi 	root_div = OV5640_PLL_CTRL3_PLL_ROOT_DIV_2;
14976c957ed7SJacopo Mondi 	bit_div =  OV5640_PLL_CTRL0_MIPI_MODE_8BIT;
14986c957ed7SJacopo Mondi 	pclk_div = ilog2(OV5640_PCLK_ROOT_DIV);
1499aa288248SMaxime Ripard 
15006c957ed7SJacopo Mondi 	/*
15016c957ed7SJacopo Mondi 	 * Scaler clock:
15026c957ed7SJacopo Mondi 	 * - YUV: PCLK >= 2 * SCLK
15036c957ed7SJacopo Mondi 	 * - RAW or JPEG: PCLK >= SCLK
15046c957ed7SJacopo Mondi 	 * - sclk2x_div = sclk_div / 2
15056c957ed7SJacopo Mondi 	 */
15066c957ed7SJacopo Mondi 	sclk_div = ilog2(OV5640_SCLK_ROOT_DIV);
15076c957ed7SJacopo Mondi 	sclk2x_div = ilog2(OV5640_SCLK2X_ROOT_DIV);
15086c957ed7SJacopo Mondi 
15096c957ed7SJacopo Mondi 	/*
15106c957ed7SJacopo Mondi 	 * Set the pixel clock period expressed in ns with 1-bit decimal
15116c957ed7SJacopo Mondi 	 * (0x01=0.5ns).
15126c957ed7SJacopo Mondi 	 *
15136c957ed7SJacopo Mondi 	 * The register is very briefly documented. In the OV5645 datasheet it
15146c957ed7SJacopo Mondi 	 * is described as (2 * pclk period), and from testing it seems the
15156c957ed7SJacopo Mondi 	 * actual definition is 2 * 8-bit sample period.
15166c957ed7SJacopo Mondi 	 *
15176c957ed7SJacopo Mondi 	 * 2 * sample_period = (mipi_clk * 2 * num_lanes / bpp) * (bpp / 8) / 2
15186c957ed7SJacopo Mondi 	 */
15196c957ed7SJacopo Mondi 	num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes;
15206c957ed7SJacopo Mondi 	sample_rate = (link_freq * mipi_div * num_lanes * 2) / 16;
15216c957ed7SJacopo Mondi 	pclk_period = 2000000000UL / sample_rate;
15226c957ed7SJacopo Mondi 
15236c957ed7SJacopo Mondi 	/* Program the clock tree registers. */
15246c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0, 0x0f, bit_div);
15256c957ed7SJacopo Mondi 	if (ret)
15266c957ed7SJacopo Mondi 		return ret;
15276c957ed7SJacopo Mondi 
15286c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, 0xff,
15296c957ed7SJacopo Mondi 			     (sysdiv << 4) | mipi_div);
1530aa288248SMaxime Ripard 	if (ret)
1531aa288248SMaxime Ripard 		return ret;
1532aa288248SMaxime Ripard 
1533aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2, 0xff, mult);
1534aa288248SMaxime Ripard 	if (ret)
1535aa288248SMaxime Ripard 		return ret;
1536aa288248SMaxime Ripard 
15376c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3, 0x1f,
15386c957ed7SJacopo Mondi 			     root_div | prediv);
1539aa288248SMaxime Ripard 	if (ret)
1540aa288248SMaxime Ripard 		return ret;
1541aa288248SMaxime Ripard 
15426c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
15436c957ed7SJacopo Mondi 			     (pclk_div << 4) | (sclk2x_div << 2) | sclk_div);
15446c957ed7SJacopo Mondi 	if (ret)
15456c957ed7SJacopo Mondi 		return ret;
15466c957ed7SJacopo Mondi 
15476c957ed7SJacopo Mondi 	return ov5640_write_reg(sensor, OV5640_REG_PCLK_PERIOD, pclk_period);
15486c957ed7SJacopo Mondi }
15496c957ed7SJacopo Mondi 
15506c957ed7SJacopo Mondi static u32 ov5640_calc_pixel_rate(struct ov5640_dev *sensor)
15516c957ed7SJacopo Mondi {
15523145efcdSJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
15535113d5b3SJacopo Mondi 	const struct ov5640_timings *timings = &mode->dvp_timings;
15546c957ed7SJacopo Mondi 	u32 rate;
15556c957ed7SJacopo Mondi 
15565113d5b3SJacopo Mondi 	rate = timings->htot * (timings->crop.height + timings->vblank_def);
15576c957ed7SJacopo Mondi 	rate *= ov5640_framerates[sensor->current_fr];
15586c957ed7SJacopo Mondi 
15596c957ed7SJacopo Mondi 	return rate;
1560aa288248SMaxime Ripard }
1561aa288248SMaxime Ripard 
1562aa288248SMaxime Ripard static unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor,
1563aa288248SMaxime Ripard 				      unsigned long rate,
1564aa288248SMaxime Ripard 				      u8 *pll_prediv, u8 *pll_mult, u8 *sysdiv,
1565aa288248SMaxime Ripard 				      u8 *pll_rdiv, u8 *bit_div, u8 *pclk_div)
1566aa288248SMaxime Ripard {
1567aa288248SMaxime Ripard 	unsigned long _rate = rate * OV5640_PLL_ROOT_DIV * OV5640_BIT_DIV *
1568aa288248SMaxime Ripard 				OV5640_PCLK_ROOT_DIV;
1569aa288248SMaxime Ripard 
1570aa288248SMaxime Ripard 	_rate = ov5640_calc_sys_clk(sensor, _rate, pll_prediv, pll_mult,
1571aa288248SMaxime Ripard 				    sysdiv);
1572aa288248SMaxime Ripard 	*pll_rdiv = OV5640_PLL_ROOT_DIV;
1573aa288248SMaxime Ripard 	*bit_div = OV5640_BIT_DIV;
1574aa288248SMaxime Ripard 	*pclk_div = OV5640_PCLK_ROOT_DIV;
1575aa288248SMaxime Ripard 
1576aa288248SMaxime Ripard 	return _rate / *pll_rdiv / *bit_div / *pclk_div;
1577aa288248SMaxime Ripard }
1578aa288248SMaxime Ripard 
15796c957ed7SJacopo Mondi static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor)
1580aa288248SMaxime Ripard {
1581aa288248SMaxime Ripard 	u8 prediv, mult, sysdiv, pll_rdiv, bit_div, pclk_div;
15826c957ed7SJacopo Mondi 	u32 rate;
1583aa288248SMaxime Ripard 	int ret;
1584aa288248SMaxime Ripard 
15856c957ed7SJacopo Mondi 	rate = ov5640_calc_pixel_rate(sensor);
1586a89f14bbSJacopo Mondi 	rate *= ov5640_code_to_bpp(sensor, sensor->fmt.code);
15876c957ed7SJacopo Mondi 	rate /= sensor->ep.bus.parallel.bus_width;
15886c957ed7SJacopo Mondi 
1589aa288248SMaxime Ripard 	ov5640_calc_pclk(sensor, rate, &prediv, &mult, &sysdiv, &pll_rdiv,
1590aa288248SMaxime Ripard 			 &bit_div, &pclk_div);
1591aa288248SMaxime Ripard 
1592aa288248SMaxime Ripard 	if (bit_div == 2)
1593aa288248SMaxime Ripard 		bit_div = 8;
1594aa288248SMaxime Ripard 
1595aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0,
1596aa288248SMaxime Ripard 			     0x0f, bit_div);
1597aa288248SMaxime Ripard 	if (ret)
1598aa288248SMaxime Ripard 		return ret;
1599aa288248SMaxime Ripard 
1600aa288248SMaxime Ripard 	/*
1601aa288248SMaxime Ripard 	 * We need to set sysdiv according to the clock, and to clear
1602aa288248SMaxime Ripard 	 * the MIPI divider.
1603aa288248SMaxime Ripard 	 */
1604aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1,
1605aa288248SMaxime Ripard 			     0xff, sysdiv << 4);
1606aa288248SMaxime Ripard 	if (ret)
1607aa288248SMaxime Ripard 		return ret;
1608aa288248SMaxime Ripard 
1609aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2,
1610aa288248SMaxime Ripard 			     0xff, mult);
1611aa288248SMaxime Ripard 	if (ret)
1612aa288248SMaxime Ripard 		return ret;
1613aa288248SMaxime Ripard 
1614aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3,
1615aa288248SMaxime Ripard 			     0x1f, prediv | ((pll_rdiv - 1) << 4));
1616aa288248SMaxime Ripard 	if (ret)
1617aa288248SMaxime Ripard 		return ret;
1618aa288248SMaxime Ripard 
1619aa288248SMaxime Ripard 	return ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x30,
1620aa288248SMaxime Ripard 			      (ilog2(pclk_div) << 4));
1621aa288248SMaxime Ripard }
1622aa288248SMaxime Ripard 
16237cb013b1SChen-Yu Tsai /* set JPEG framing sizes */
16247cb013b1SChen-Yu Tsai static int ov5640_set_jpeg_timings(struct ov5640_dev *sensor,
16257cb013b1SChen-Yu Tsai 				   const struct ov5640_mode_info *mode)
16267cb013b1SChen-Yu Tsai {
16277cb013b1SChen-Yu Tsai 	int ret;
16287cb013b1SChen-Yu Tsai 
16292b5c18f9SChen-Yu Tsai 	/*
16302b5c18f9SChen-Yu Tsai 	 * compression mode 3 timing
16312b5c18f9SChen-Yu Tsai 	 *
16322b5c18f9SChen-Yu Tsai 	 * Data is transmitted with programmable width (VFIFO_HSIZE).
16332b5c18f9SChen-Yu Tsai 	 * No padding done. Last line may have less data. Varying
16342b5c18f9SChen-Yu Tsai 	 * number of lines per frame, depending on amount of data.
16352b5c18f9SChen-Yu Tsai 	 */
16362b5c18f9SChen-Yu Tsai 	ret = ov5640_mod_reg(sensor, OV5640_REG_JPG_MODE_SELECT, 0x7, 0x3);
16372b5c18f9SChen-Yu Tsai 	if (ret < 0)
16382b5c18f9SChen-Yu Tsai 		return ret;
16392b5c18f9SChen-Yu Tsai 
16405113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_VFIFO_HSIZE, mode->width);
16417cb013b1SChen-Yu Tsai 	if (ret < 0)
16427cb013b1SChen-Yu Tsai 		return ret;
16437cb013b1SChen-Yu Tsai 
16445113d5b3SJacopo Mondi 	return ov5640_write_reg16(sensor, OV5640_REG_VFIFO_VSIZE, mode->height);
16457cb013b1SChen-Yu Tsai }
16467cb013b1SChen-Yu Tsai 
164719a81c14SSteve Longerbeam /* download ov5640 settings to sensor through i2c */
1648bad1774eSJacopo Mondi static int ov5640_set_timings(struct ov5640_dev *sensor,
1649bad1774eSJacopo Mondi 			      const struct ov5640_mode_info *mode)
1650bad1774eSJacopo Mondi {
16515113d5b3SJacopo Mondi 	const struct ov5640_timings *timings;
16525113d5b3SJacopo Mondi 	const struct v4l2_rect *analog_crop;
16535113d5b3SJacopo Mondi 	const struct v4l2_rect *crop;
1654bad1774eSJacopo Mondi 	int ret;
1655bad1774eSJacopo Mondi 
16567cb013b1SChen-Yu Tsai 	if (sensor->fmt.code == MEDIA_BUS_FMT_JPEG_1X8) {
16577cb013b1SChen-Yu Tsai 		ret = ov5640_set_jpeg_timings(sensor, mode);
16587cb013b1SChen-Yu Tsai 		if (ret < 0)
16597cb013b1SChen-Yu Tsai 			return ret;
16607cb013b1SChen-Yu Tsai 	}
16617cb013b1SChen-Yu Tsai 
16622de6bb97SJacopo Mondi 	timings = ov5640_timings(sensor, mode);
16635113d5b3SJacopo Mondi 	analog_crop = &timings->analog_crop;
16645113d5b3SJacopo Mondi 	crop = &timings->crop;
16655113d5b3SJacopo Mondi 
16663145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HS,
16673145efcdSJacopo Mondi 				 analog_crop->left);
1668bad1774eSJacopo Mondi 	if (ret < 0)
1669bad1774eSJacopo Mondi 		return ret;
1670bad1774eSJacopo Mondi 
16713145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VS,
16723145efcdSJacopo Mondi 				 analog_crop->top);
16733145efcdSJacopo Mondi 	if (ret < 0)
16743145efcdSJacopo Mondi 		return ret;
16753145efcdSJacopo Mondi 
16763145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HW,
16773145efcdSJacopo Mondi 				 analog_crop->left + analog_crop->width - 1);
16783145efcdSJacopo Mondi 	if (ret < 0)
16793145efcdSJacopo Mondi 		return ret;
16803145efcdSJacopo Mondi 
16813145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VH,
16823145efcdSJacopo Mondi 				 analog_crop->top + analog_crop->height - 1);
16833145efcdSJacopo Mondi 	if (ret < 0)
16843145efcdSJacopo Mondi 		return ret;
16853145efcdSJacopo Mondi 
16863145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HOFFS, crop->left);
16873145efcdSJacopo Mondi 	if (ret < 0)
16883145efcdSJacopo Mondi 		return ret;
16893145efcdSJacopo Mondi 
16903145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VOFFS, crop->top);
16913145efcdSJacopo Mondi 	if (ret < 0)
16923145efcdSJacopo Mondi 		return ret;
16933145efcdSJacopo Mondi 
16945113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->width);
16953145efcdSJacopo Mondi 	if (ret < 0)
16963145efcdSJacopo Mondi 		return ret;
16973145efcdSJacopo Mondi 
16985113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, mode->height);
1699bad1774eSJacopo Mondi 	if (ret < 0)
1700bad1774eSJacopo Mondi 		return ret;
1701bad1774eSJacopo Mondi 
17025113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, timings->htot);
1703bad1774eSJacopo Mondi 	if (ret < 0)
1704bad1774eSJacopo Mondi 		return ret;
1705bad1774eSJacopo Mondi 
17063145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS,
17075113d5b3SJacopo Mondi 				 mode->height + timings->vblank_def);
17083145efcdSJacopo Mondi 	if (ret < 0)
17093145efcdSJacopo Mondi 		return ret;
17103145efcdSJacopo Mondi 
17113145efcdSJacopo Mondi 	return 0;
1712bad1774eSJacopo Mondi }
1713bad1774eSJacopo Mondi 
1714e4359019SJacopo Mondi static void ov5640_load_regs(struct ov5640_dev *sensor,
1715e4359019SJacopo Mondi 			     const struct reg_value *regs, unsigned int regnum)
171619a81c14SSteve Longerbeam {
171719a81c14SSteve Longerbeam 	unsigned int i;
171819a81c14SSteve Longerbeam 	u32 delay_ms;
171919a81c14SSteve Longerbeam 	u16 reg_addr;
172019a81c14SSteve Longerbeam 	u8 mask, val;
172119a81c14SSteve Longerbeam 	int ret = 0;
172219a81c14SSteve Longerbeam 
1723e4359019SJacopo Mondi 	for (i = 0; i < regnum; ++i, ++regs) {
172419a81c14SSteve Longerbeam 		delay_ms = regs->delay_ms;
172519a81c14SSteve Longerbeam 		reg_addr = regs->reg_addr;
172619a81c14SSteve Longerbeam 		val = regs->val;
172719a81c14SSteve Longerbeam 		mask = regs->mask;
172819a81c14SSteve Longerbeam 
17293b987d70SLad Prabhakar 		/* remain in power down mode for DVP */
17303b987d70SLad Prabhakar 		if (regs->reg_addr == OV5640_REG_SYS_CTRL0 &&
17313b987d70SLad Prabhakar 		    val == OV5640_REG_SYS_CTRL0_SW_PWUP &&
17328e823f5cSJacopo Mondi 		    !ov5640_is_csi2(sensor))
17333b987d70SLad Prabhakar 			continue;
17343b987d70SLad Prabhakar 
173519a81c14SSteve Longerbeam 		if (mask)
173619a81c14SSteve Longerbeam 			ret = ov5640_mod_reg(sensor, reg_addr, mask, val);
173719a81c14SSteve Longerbeam 		else
173819a81c14SSteve Longerbeam 			ret = ov5640_write_reg(sensor, reg_addr, val);
173919a81c14SSteve Longerbeam 		if (ret)
174019a81c14SSteve Longerbeam 			break;
174119a81c14SSteve Longerbeam 
174219a81c14SSteve Longerbeam 		if (delay_ms)
174319a81c14SSteve Longerbeam 			usleep_range(1000 * delay_ms, 1000 * delay_ms + 100);
174419a81c14SSteve Longerbeam 	}
174519a81c14SSteve Longerbeam }
174619a81c14SSteve Longerbeam 
1747dc29a1c1SHugues Fruchet static int ov5640_set_autoexposure(struct ov5640_dev *sensor, bool on)
1748dc29a1c1SHugues Fruchet {
1749dc29a1c1SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
1750dc29a1c1SHugues Fruchet 			      BIT(0), on ? 0 : BIT(0));
1751dc29a1c1SHugues Fruchet }
1752dc29a1c1SHugues Fruchet 
175319a81c14SSteve Longerbeam /* read exposure, in number of line periods */
175419a81c14SSteve Longerbeam static int ov5640_get_exposure(struct ov5640_dev *sensor)
175519a81c14SSteve Longerbeam {
175619a81c14SSteve Longerbeam 	int exp, ret;
175719a81c14SSteve Longerbeam 	u8 temp;
175819a81c14SSteve Longerbeam 
175919a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_HI, &temp);
176019a81c14SSteve Longerbeam 	if (ret)
176119a81c14SSteve Longerbeam 		return ret;
176219a81c14SSteve Longerbeam 	exp = ((int)temp & 0x0f) << 16;
176319a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_MED, &temp);
176419a81c14SSteve Longerbeam 	if (ret)
176519a81c14SSteve Longerbeam 		return ret;
176619a81c14SSteve Longerbeam 	exp |= ((int)temp << 8);
176719a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_LO, &temp);
176819a81c14SSteve Longerbeam 	if (ret)
176919a81c14SSteve Longerbeam 		return ret;
177019a81c14SSteve Longerbeam 	exp |= (int)temp;
177119a81c14SSteve Longerbeam 
177219a81c14SSteve Longerbeam 	return exp >> 4;
177319a81c14SSteve Longerbeam }
177419a81c14SSteve Longerbeam 
177519a81c14SSteve Longerbeam /* write exposure, given number of line periods */
177619a81c14SSteve Longerbeam static int ov5640_set_exposure(struct ov5640_dev *sensor, u32 exposure)
177719a81c14SSteve Longerbeam {
177819a81c14SSteve Longerbeam 	int ret;
177919a81c14SSteve Longerbeam 
178019a81c14SSteve Longerbeam 	exposure <<= 4;
178119a81c14SSteve Longerbeam 
178219a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor,
178319a81c14SSteve Longerbeam 			       OV5640_REG_AEC_PK_EXPOSURE_LO,
178419a81c14SSteve Longerbeam 			       exposure & 0xff);
178519a81c14SSteve Longerbeam 	if (ret)
178619a81c14SSteve Longerbeam 		return ret;
178719a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor,
178819a81c14SSteve Longerbeam 			       OV5640_REG_AEC_PK_EXPOSURE_MED,
178919a81c14SSteve Longerbeam 			       (exposure >> 8) & 0xff);
179019a81c14SSteve Longerbeam 	if (ret)
179119a81c14SSteve Longerbeam 		return ret;
179219a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor,
179319a81c14SSteve Longerbeam 				OV5640_REG_AEC_PK_EXPOSURE_HI,
179419a81c14SSteve Longerbeam 				(exposure >> 16) & 0x0f);
179519a81c14SSteve Longerbeam }
179619a81c14SSteve Longerbeam 
179719a81c14SSteve Longerbeam static int ov5640_get_gain(struct ov5640_dev *sensor)
179819a81c14SSteve Longerbeam {
179919a81c14SSteve Longerbeam 	u16 gain;
180019a81c14SSteve Longerbeam 	int ret;
180119a81c14SSteve Longerbeam 
180219a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN, &gain);
180319a81c14SSteve Longerbeam 	if (ret)
180419a81c14SSteve Longerbeam 		return ret;
180519a81c14SSteve Longerbeam 
180619a81c14SSteve Longerbeam 	return gain & 0x3ff;
180719a81c14SSteve Longerbeam }
180819a81c14SSteve Longerbeam 
18093cca8ef5SHugues Fruchet static int ov5640_set_gain(struct ov5640_dev *sensor, int gain)
18103cca8ef5SHugues Fruchet {
18113cca8ef5SHugues Fruchet 	return ov5640_write_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN,
18123cca8ef5SHugues Fruchet 				  (u16)gain & 0x3ff);
18133cca8ef5SHugues Fruchet }
18143cca8ef5SHugues Fruchet 
18153cca8ef5SHugues Fruchet static int ov5640_set_autogain(struct ov5640_dev *sensor, bool on)
18163cca8ef5SHugues Fruchet {
18173cca8ef5SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
18183cca8ef5SHugues Fruchet 			      BIT(1), on ? 0 : BIT(1));
18193cca8ef5SHugues Fruchet }
18203cca8ef5SHugues Fruchet 
1821f22996dbSHugues Fruchet static int ov5640_set_stream_dvp(struct ov5640_dev *sensor, bool on)
1822f22996dbSHugues Fruchet {
18233b987d70SLad Prabhakar 	return ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0, on ?
18243b987d70SLad Prabhakar 				OV5640_REG_SYS_CTRL0_SW_PWUP :
18253b987d70SLad Prabhakar 				OV5640_REG_SYS_CTRL0_SW_PWDN);
1826f22996dbSHugues Fruchet }
1827f22996dbSHugues Fruchet 
1828f22996dbSHugues Fruchet static int ov5640_set_stream_mipi(struct ov5640_dev *sensor, bool on)
182919a81c14SSteve Longerbeam {
183019a81c14SSteve Longerbeam 	int ret;
183119a81c14SSteve Longerbeam 
1832aa4bb8b8SJacopo Mondi 	/*
1833aa4bb8b8SJacopo Mondi 	 * Enable/disable the MIPI interface
1834aa4bb8b8SJacopo Mondi 	 *
1835aa4bb8b8SJacopo Mondi 	 * 0x300e = on ? 0x45 : 0x40
1836aa4bb8b8SJacopo Mondi 	 *
1837aa4bb8b8SJacopo Mondi 	 * FIXME: the sensor manual (version 2.03) reports
1838aa4bb8b8SJacopo Mondi 	 * [7:5] = 000  : 1 data lane mode
1839aa4bb8b8SJacopo Mondi 	 * [7:5] = 001  : 2 data lanes mode
1840aa4bb8b8SJacopo Mondi 	 * But this settings do not work, while the following ones
1841aa4bb8b8SJacopo Mondi 	 * have been validated for 2 data lanes mode.
1842aa4bb8b8SJacopo Mondi 	 *
1843aa4bb8b8SJacopo Mondi 	 * [7:5] = 010	: 2 data lanes mode
1844aa4bb8b8SJacopo Mondi 	 * [4] = 0	: Power up MIPI HS Tx
1845aa4bb8b8SJacopo Mondi 	 * [3] = 0	: Power up MIPI LS Rx
1846aa4bb8b8SJacopo Mondi 	 * [2] = 1/0	: MIPI interface enable/disable
1847aa4bb8b8SJacopo Mondi 	 * [1:0] = 01/00: FIXME: 'debug'
1848aa4bb8b8SJacopo Mondi 	 */
1849aa4bb8b8SJacopo Mondi 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00,
1850aa4bb8b8SJacopo Mondi 			       on ? 0x45 : 0x40);
185119a81c14SSteve Longerbeam 	if (ret)
185219a81c14SSteve Longerbeam 		return ret;
185319a81c14SSteve Longerbeam 
185419a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_FRAME_CTRL01,
185519a81c14SSteve Longerbeam 				on ? 0x00 : 0x0f);
185619a81c14SSteve Longerbeam }
185719a81c14SSteve Longerbeam 
185819a81c14SSteve Longerbeam static int ov5640_get_sysclk(struct ov5640_dev *sensor)
185919a81c14SSteve Longerbeam {
186019a81c14SSteve Longerbeam 	 /* calculate sysclk */
186119a81c14SSteve Longerbeam 	u32 xvclk = sensor->xclk_freq / 10000;
186219a81c14SSteve Longerbeam 	u32 multiplier, prediv, VCO, sysdiv, pll_rdiv;
186319a81c14SSteve Longerbeam 	u32 sclk_rdiv_map[] = {1, 2, 4, 8};
186419a81c14SSteve Longerbeam 	u32 bit_div2x = 1, sclk_rdiv, sysclk;
186519a81c14SSteve Longerbeam 	u8 temp1, temp2;
186619a81c14SSteve Longerbeam 	int ret;
186719a81c14SSteve Longerbeam 
186819a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL0, &temp1);
186919a81c14SSteve Longerbeam 	if (ret)
187019a81c14SSteve Longerbeam 		return ret;
187119a81c14SSteve Longerbeam 	temp2 = temp1 & 0x0f;
187219a81c14SSteve Longerbeam 	if (temp2 == 8 || temp2 == 10)
187319a81c14SSteve Longerbeam 		bit_div2x = temp2 / 2;
187419a81c14SSteve Longerbeam 
187519a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL1, &temp1);
187619a81c14SSteve Longerbeam 	if (ret)
187719a81c14SSteve Longerbeam 		return ret;
187819a81c14SSteve Longerbeam 	sysdiv = temp1 >> 4;
187919a81c14SSteve Longerbeam 	if (sysdiv == 0)
188019a81c14SSteve Longerbeam 		sysdiv = 16;
188119a81c14SSteve Longerbeam 
188219a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL2, &temp1);
188319a81c14SSteve Longerbeam 	if (ret)
188419a81c14SSteve Longerbeam 		return ret;
188519a81c14SSteve Longerbeam 	multiplier = temp1;
188619a81c14SSteve Longerbeam 
188719a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL3, &temp1);
188819a81c14SSteve Longerbeam 	if (ret)
188919a81c14SSteve Longerbeam 		return ret;
189019a81c14SSteve Longerbeam 	prediv = temp1 & 0x0f;
189119a81c14SSteve Longerbeam 	pll_rdiv = ((temp1 >> 4) & 0x01) + 1;
189219a81c14SSteve Longerbeam 
189319a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, &temp1);
189419a81c14SSteve Longerbeam 	if (ret)
189519a81c14SSteve Longerbeam 		return ret;
189619a81c14SSteve Longerbeam 	temp2 = temp1 & 0x03;
189719a81c14SSteve Longerbeam 	sclk_rdiv = sclk_rdiv_map[temp2];
189819a81c14SSteve Longerbeam 
189919a81c14SSteve Longerbeam 	if (!prediv || !sysdiv || !pll_rdiv || !bit_div2x)
190019a81c14SSteve Longerbeam 		return -EINVAL;
190119a81c14SSteve Longerbeam 
190219a81c14SSteve Longerbeam 	VCO = xvclk * multiplier / prediv;
190319a81c14SSteve Longerbeam 
190419a81c14SSteve Longerbeam 	sysclk = VCO / sysdiv / pll_rdiv * 2 / bit_div2x / sclk_rdiv;
190519a81c14SSteve Longerbeam 
190619a81c14SSteve Longerbeam 	return sysclk;
190719a81c14SSteve Longerbeam }
190819a81c14SSteve Longerbeam 
190919a81c14SSteve Longerbeam static int ov5640_set_night_mode(struct ov5640_dev *sensor)
191019a81c14SSteve Longerbeam {
191119a81c14SSteve Longerbeam 	 /* read HTS from register settings */
191219a81c14SSteve Longerbeam 	u8 mode;
191319a81c14SSteve Longerbeam 	int ret;
191419a81c14SSteve Longerbeam 
191519a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_CTRL00, &mode);
191619a81c14SSteve Longerbeam 	if (ret)
191719a81c14SSteve Longerbeam 		return ret;
191819a81c14SSteve Longerbeam 	mode &= 0xfb;
191919a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL00, mode);
192019a81c14SSteve Longerbeam }
192119a81c14SSteve Longerbeam 
192219a81c14SSteve Longerbeam static int ov5640_get_hts(struct ov5640_dev *sensor)
192319a81c14SSteve Longerbeam {
192419a81c14SSteve Longerbeam 	/* read HTS from register settings */
192519a81c14SSteve Longerbeam 	u16 hts;
192619a81c14SSteve Longerbeam 	int ret;
192719a81c14SSteve Longerbeam 
192819a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_HTS, &hts);
192919a81c14SSteve Longerbeam 	if (ret)
193019a81c14SSteve Longerbeam 		return ret;
193119a81c14SSteve Longerbeam 	return hts;
193219a81c14SSteve Longerbeam }
193319a81c14SSteve Longerbeam 
193419a81c14SSteve Longerbeam static int ov5640_get_vts(struct ov5640_dev *sensor)
193519a81c14SSteve Longerbeam {
193619a81c14SSteve Longerbeam 	u16 vts;
193719a81c14SSteve Longerbeam 	int ret;
193819a81c14SSteve Longerbeam 
193919a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_VTS, &vts);
194019a81c14SSteve Longerbeam 	if (ret)
194119a81c14SSteve Longerbeam 		return ret;
194219a81c14SSteve Longerbeam 	return vts;
194319a81c14SSteve Longerbeam }
194419a81c14SSteve Longerbeam 
194519a81c14SSteve Longerbeam static int ov5640_set_vts(struct ov5640_dev *sensor, int vts)
194619a81c14SSteve Longerbeam {
194719a81c14SSteve Longerbeam 	return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, vts);
194819a81c14SSteve Longerbeam }
194919a81c14SSteve Longerbeam 
195019a81c14SSteve Longerbeam static int ov5640_get_light_freq(struct ov5640_dev *sensor)
195119a81c14SSteve Longerbeam {
195219a81c14SSteve Longerbeam 	/* get banding filter value */
195319a81c14SSteve Longerbeam 	int ret, light_freq = 0;
195419a81c14SSteve Longerbeam 	u8 temp, temp1;
195519a81c14SSteve Longerbeam 
195619a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL01, &temp);
195719a81c14SSteve Longerbeam 	if (ret)
195819a81c14SSteve Longerbeam 		return ret;
195919a81c14SSteve Longerbeam 
196019a81c14SSteve Longerbeam 	if (temp & 0x80) {
196119a81c14SSteve Longerbeam 		/* manual */
196219a81c14SSteve Longerbeam 		ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL00,
196319a81c14SSteve Longerbeam 				      &temp1);
196419a81c14SSteve Longerbeam 		if (ret)
196519a81c14SSteve Longerbeam 			return ret;
196619a81c14SSteve Longerbeam 		if (temp1 & 0x04) {
196719a81c14SSteve Longerbeam 			/* 50Hz */
196819a81c14SSteve Longerbeam 			light_freq = 50;
196919a81c14SSteve Longerbeam 		} else {
197019a81c14SSteve Longerbeam 			/* 60Hz */
197119a81c14SSteve Longerbeam 			light_freq = 60;
197219a81c14SSteve Longerbeam 		}
197319a81c14SSteve Longerbeam 	} else {
197419a81c14SSteve Longerbeam 		/* auto */
197519a81c14SSteve Longerbeam 		ret = ov5640_read_reg(sensor, OV5640_REG_SIGMADELTA_CTRL0C,
197619a81c14SSteve Longerbeam 				      &temp1);
197719a81c14SSteve Longerbeam 		if (ret)
197819a81c14SSteve Longerbeam 			return ret;
197919a81c14SSteve Longerbeam 
198019a81c14SSteve Longerbeam 		if (temp1 & 0x01) {
198119a81c14SSteve Longerbeam 			/* 50Hz */
198219a81c14SSteve Longerbeam 			light_freq = 50;
198319a81c14SSteve Longerbeam 		} else {
198419a81c14SSteve Longerbeam 			/* 60Hz */
198519a81c14SSteve Longerbeam 		}
198619a81c14SSteve Longerbeam 	}
198719a81c14SSteve Longerbeam 
198819a81c14SSteve Longerbeam 	return light_freq;
198919a81c14SSteve Longerbeam }
199019a81c14SSteve Longerbeam 
199119a81c14SSteve Longerbeam static int ov5640_set_bandingfilter(struct ov5640_dev *sensor)
199219a81c14SSteve Longerbeam {
199319a81c14SSteve Longerbeam 	u32 band_step60, max_band60, band_step50, max_band50, prev_vts;
199419a81c14SSteve Longerbeam 	int ret;
199519a81c14SSteve Longerbeam 
199619a81c14SSteve Longerbeam 	/* read preview PCLK */
199719a81c14SSteve Longerbeam 	ret = ov5640_get_sysclk(sensor);
199819a81c14SSteve Longerbeam 	if (ret < 0)
199919a81c14SSteve Longerbeam 		return ret;
200019a81c14SSteve Longerbeam 	if (ret == 0)
200119a81c14SSteve Longerbeam 		return -EINVAL;
200219a81c14SSteve Longerbeam 	sensor->prev_sysclk = ret;
200319a81c14SSteve Longerbeam 	/* read preview HTS */
200419a81c14SSteve Longerbeam 	ret = ov5640_get_hts(sensor);
200519a81c14SSteve Longerbeam 	if (ret < 0)
200619a81c14SSteve Longerbeam 		return ret;
200719a81c14SSteve Longerbeam 	if (ret == 0)
200819a81c14SSteve Longerbeam 		return -EINVAL;
200919a81c14SSteve Longerbeam 	sensor->prev_hts = ret;
201019a81c14SSteve Longerbeam 
201119a81c14SSteve Longerbeam 	/* read preview VTS */
201219a81c14SSteve Longerbeam 	ret = ov5640_get_vts(sensor);
201319a81c14SSteve Longerbeam 	if (ret < 0)
201419a81c14SSteve Longerbeam 		return ret;
201519a81c14SSteve Longerbeam 	prev_vts = ret;
201619a81c14SSteve Longerbeam 
201719a81c14SSteve Longerbeam 	/* calculate banding filter */
201819a81c14SSteve Longerbeam 	/* 60Hz */
201919a81c14SSteve Longerbeam 	band_step60 = sensor->prev_sysclk * 100 / sensor->prev_hts * 100 / 120;
202019a81c14SSteve Longerbeam 	ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B60_STEP, band_step60);
202119a81c14SSteve Longerbeam 	if (ret)
202219a81c14SSteve Longerbeam 		return ret;
202319a81c14SSteve Longerbeam 	if (!band_step60)
202419a81c14SSteve Longerbeam 		return -EINVAL;
202519a81c14SSteve Longerbeam 	max_band60 = (int)((prev_vts - 4) / band_step60);
202619a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0D, max_band60);
202719a81c14SSteve Longerbeam 	if (ret)
202819a81c14SSteve Longerbeam 		return ret;
202919a81c14SSteve Longerbeam 
203019a81c14SSteve Longerbeam 	/* 50Hz */
203119a81c14SSteve Longerbeam 	band_step50 = sensor->prev_sysclk * 100 / sensor->prev_hts;
203219a81c14SSteve Longerbeam 	ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B50_STEP, band_step50);
203319a81c14SSteve Longerbeam 	if (ret)
203419a81c14SSteve Longerbeam 		return ret;
203519a81c14SSteve Longerbeam 	if (!band_step50)
203619a81c14SSteve Longerbeam 		return -EINVAL;
203719a81c14SSteve Longerbeam 	max_band50 = (int)((prev_vts - 4) / band_step50);
203819a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0E, max_band50);
203919a81c14SSteve Longerbeam }
204019a81c14SSteve Longerbeam 
204119a81c14SSteve Longerbeam static int ov5640_set_ae_target(struct ov5640_dev *sensor, int target)
204219a81c14SSteve Longerbeam {
204319a81c14SSteve Longerbeam 	/* stable in high */
204419a81c14SSteve Longerbeam 	u32 fast_high, fast_low;
204519a81c14SSteve Longerbeam 	int ret;
204619a81c14SSteve Longerbeam 
204719a81c14SSteve Longerbeam 	sensor->ae_low = target * 23 / 25;	/* 0.92 */
204819a81c14SSteve Longerbeam 	sensor->ae_high = target * 27 / 25;	/* 1.08 */
204919a81c14SSteve Longerbeam 
205019a81c14SSteve Longerbeam 	fast_high = sensor->ae_high << 1;
205119a81c14SSteve Longerbeam 	if (fast_high > 255)
205219a81c14SSteve Longerbeam 		fast_high = 255;
205319a81c14SSteve Longerbeam 
205419a81c14SSteve Longerbeam 	fast_low = sensor->ae_low >> 1;
205519a81c14SSteve Longerbeam 
205619a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0F, sensor->ae_high);
205719a81c14SSteve Longerbeam 	if (ret)
205819a81c14SSteve Longerbeam 		return ret;
205919a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL10, sensor->ae_low);
206019a81c14SSteve Longerbeam 	if (ret)
206119a81c14SSteve Longerbeam 		return ret;
206219a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1B, sensor->ae_high);
206319a81c14SSteve Longerbeam 	if (ret)
206419a81c14SSteve Longerbeam 		return ret;
206519a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1E, sensor->ae_low);
206619a81c14SSteve Longerbeam 	if (ret)
206719a81c14SSteve Longerbeam 		return ret;
206819a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL11, fast_high);
206919a81c14SSteve Longerbeam 	if (ret)
207019a81c14SSteve Longerbeam 		return ret;
207119a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1F, fast_low);
207219a81c14SSteve Longerbeam }
207319a81c14SSteve Longerbeam 
2074c2c3f42dSHugues Fruchet static int ov5640_get_binning(struct ov5640_dev *sensor)
207519a81c14SSteve Longerbeam {
207619a81c14SSteve Longerbeam 	u8 temp;
207719a81c14SSteve Longerbeam 	int ret;
207819a81c14SSteve Longerbeam 
207919a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_TIMING_TC_REG21, &temp);
208019a81c14SSteve Longerbeam 	if (ret)
208119a81c14SSteve Longerbeam 		return ret;
2082c2c3f42dSHugues Fruchet 
2083c2c3f42dSHugues Fruchet 	return temp & BIT(0);
208419a81c14SSteve Longerbeam }
208519a81c14SSteve Longerbeam 
2086ce85705aSHugues Fruchet static int ov5640_set_binning(struct ov5640_dev *sensor, bool enable)
2087ce85705aSHugues Fruchet {
2088ce85705aSHugues Fruchet 	int ret;
2089ce85705aSHugues Fruchet 
2090ce85705aSHugues Fruchet 	/*
2091ce85705aSHugues Fruchet 	 * TIMING TC REG21:
2092ce85705aSHugues Fruchet 	 * - [0]:	Horizontal binning enable
2093ce85705aSHugues Fruchet 	 */
2094ce85705aSHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
2095ce85705aSHugues Fruchet 			     BIT(0), enable ? BIT(0) : 0);
2096ce85705aSHugues Fruchet 	if (ret)
2097ce85705aSHugues Fruchet 		return ret;
2098ce85705aSHugues Fruchet 	/*
2099ce85705aSHugues Fruchet 	 * TIMING TC REG20:
2100ce85705aSHugues Fruchet 	 * - [0]:	Undocumented, but hardcoded init sequences
2101ce85705aSHugues Fruchet 	 *		are always setting REG21/REG20 bit 0 to same value...
2102ce85705aSHugues Fruchet 	 */
2103ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20,
2104ce85705aSHugues Fruchet 			      BIT(0), enable ? BIT(0) : 0);
2105ce85705aSHugues Fruchet }
2106ce85705aSHugues Fruchet 
210719a81c14SSteve Longerbeam static int ov5640_set_virtual_channel(struct ov5640_dev *sensor)
210819a81c14SSteve Longerbeam {
21098670d70aSHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
211019a81c14SSteve Longerbeam 	u8 temp, channel = virtual_channel;
211119a81c14SSteve Longerbeam 	int ret;
211219a81c14SSteve Longerbeam 
21138670d70aSHugues Fruchet 	if (channel > 3) {
21148670d70aSHugues Fruchet 		dev_err(&client->dev,
21158670d70aSHugues Fruchet 			"%s: wrong virtual_channel parameter, expected (0..3), got %d\n",
21168670d70aSHugues Fruchet 			__func__, channel);
211719a81c14SSteve Longerbeam 		return -EINVAL;
21188670d70aSHugues Fruchet 	}
211919a81c14SSteve Longerbeam 
212019a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_DEBUG_MODE, &temp);
212119a81c14SSteve Longerbeam 	if (ret)
212219a81c14SSteve Longerbeam 		return ret;
212319a81c14SSteve Longerbeam 	temp &= ~(3 << 6);
212419a81c14SSteve Longerbeam 	temp |= (channel << 6);
212519a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_DEBUG_MODE, temp);
212619a81c14SSteve Longerbeam }
212719a81c14SSteve Longerbeam 
212819a81c14SSteve Longerbeam static const struct ov5640_mode_info *
2129b6ae5022SJacopo Mondi ov5640_find_mode(struct ov5640_dev *sensor, int width, int height, bool nearest)
213019a81c14SSteve Longerbeam {
21313c4a7372SHugues Fruchet 	const struct ov5640_mode_info *mode;
213219a81c14SSteve Longerbeam 
2133086c25f8SMaxime Ripard 	mode = v4l2_find_nearest_size(ov5640_mode_data,
2134086c25f8SMaxime Ripard 				      ARRAY_SIZE(ov5640_mode_data),
21355113d5b3SJacopo Mondi 				      width, height, width, height);
213619a81c14SSteve Longerbeam 
21373c4a7372SHugues Fruchet 	if (!mode ||
21383145efcdSJacopo Mondi 	    (!nearest &&
21395113d5b3SJacopo Mondi 	     (mode->width != width || mode->height != height)))
21403c4a7372SHugues Fruchet 		return NULL;
214119a81c14SSteve Longerbeam 
214219a81c14SSteve Longerbeam 	return mode;
214319a81c14SSteve Longerbeam }
214419a81c14SSteve Longerbeam 
214519a81c14SSteve Longerbeam /*
214619a81c14SSteve Longerbeam  * sensor changes between scaling and subsampling, go through
214719a81c14SSteve Longerbeam  * exposure calculation
214819a81c14SSteve Longerbeam  */
214941d8d7f5SHugues Fruchet static int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor,
215041d8d7f5SHugues Fruchet 					 const struct ov5640_mode_info *mode)
215119a81c14SSteve Longerbeam {
215219a81c14SSteve Longerbeam 	u32 prev_shutter, prev_gain16;
215319a81c14SSteve Longerbeam 	u32 cap_shutter, cap_gain16;
215419a81c14SSteve Longerbeam 	u32 cap_sysclk, cap_hts, cap_vts;
215519a81c14SSteve Longerbeam 	u32 light_freq, cap_bandfilt, cap_maxband;
215619a81c14SSteve Longerbeam 	u32 cap_gain16_shutter;
215719a81c14SSteve Longerbeam 	u8 average;
215819a81c14SSteve Longerbeam 	int ret;
215919a81c14SSteve Longerbeam 
216041d8d7f5SHugues Fruchet 	if (!mode->reg_data)
216119a81c14SSteve Longerbeam 		return -EINVAL;
216219a81c14SSteve Longerbeam 
216319a81c14SSteve Longerbeam 	/* read preview shutter */
216419a81c14SSteve Longerbeam 	ret = ov5640_get_exposure(sensor);
216519a81c14SSteve Longerbeam 	if (ret < 0)
216619a81c14SSteve Longerbeam 		return ret;
216719a81c14SSteve Longerbeam 	prev_shutter = ret;
2168c2c3f42dSHugues Fruchet 	ret = ov5640_get_binning(sensor);
216919a81c14SSteve Longerbeam 	if (ret < 0)
217019a81c14SSteve Longerbeam 		return ret;
217119a81c14SSteve Longerbeam 	if (ret && mode->id != OV5640_MODE_720P_1280_720 &&
217219a81c14SSteve Longerbeam 	    mode->id != OV5640_MODE_1080P_1920_1080)
217319a81c14SSteve Longerbeam 		prev_shutter *= 2;
217419a81c14SSteve Longerbeam 
217519a81c14SSteve Longerbeam 	/* read preview gain */
217619a81c14SSteve Longerbeam 	ret = ov5640_get_gain(sensor);
217719a81c14SSteve Longerbeam 	if (ret < 0)
217819a81c14SSteve Longerbeam 		return ret;
217919a81c14SSteve Longerbeam 	prev_gain16 = ret;
218019a81c14SSteve Longerbeam 
218119a81c14SSteve Longerbeam 	/* get average */
218219a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AVG_READOUT, &average);
218319a81c14SSteve Longerbeam 	if (ret)
218419a81c14SSteve Longerbeam 		return ret;
218519a81c14SSteve Longerbeam 
218619a81c14SSteve Longerbeam 	/* turn off night mode for capture */
218719a81c14SSteve Longerbeam 	ret = ov5640_set_night_mode(sensor);
218819a81c14SSteve Longerbeam 	if (ret < 0)
218919a81c14SSteve Longerbeam 		return ret;
219019a81c14SSteve Longerbeam 
219119a81c14SSteve Longerbeam 	/* Write capture setting */
2192e4359019SJacopo Mondi 	ov5640_load_regs(sensor, mode->reg_data, mode->reg_data_size);
2193e4359019SJacopo Mondi 	ret = ov5640_set_timings(sensor, mode);
219419a81c14SSteve Longerbeam 	if (ret < 0)
219519a81c14SSteve Longerbeam 		return ret;
219619a81c14SSteve Longerbeam 
219719a81c14SSteve Longerbeam 	/* read capture VTS */
219819a81c14SSteve Longerbeam 	ret = ov5640_get_vts(sensor);
219919a81c14SSteve Longerbeam 	if (ret < 0)
220019a81c14SSteve Longerbeam 		return ret;
220119a81c14SSteve Longerbeam 	cap_vts = ret;
220219a81c14SSteve Longerbeam 	ret = ov5640_get_hts(sensor);
220319a81c14SSteve Longerbeam 	if (ret < 0)
220419a81c14SSteve Longerbeam 		return ret;
220519a81c14SSteve Longerbeam 	if (ret == 0)
220619a81c14SSteve Longerbeam 		return -EINVAL;
220719a81c14SSteve Longerbeam 	cap_hts = ret;
220819a81c14SSteve Longerbeam 
220919a81c14SSteve Longerbeam 	ret = ov5640_get_sysclk(sensor);
221019a81c14SSteve Longerbeam 	if (ret < 0)
221119a81c14SSteve Longerbeam 		return ret;
221219a81c14SSteve Longerbeam 	if (ret == 0)
221319a81c14SSteve Longerbeam 		return -EINVAL;
221419a81c14SSteve Longerbeam 	cap_sysclk = ret;
221519a81c14SSteve Longerbeam 
221619a81c14SSteve Longerbeam 	/* calculate capture banding filter */
221719a81c14SSteve Longerbeam 	ret = ov5640_get_light_freq(sensor);
221819a81c14SSteve Longerbeam 	if (ret < 0)
221919a81c14SSteve Longerbeam 		return ret;
222019a81c14SSteve Longerbeam 	light_freq = ret;
222119a81c14SSteve Longerbeam 
222219a81c14SSteve Longerbeam 	if (light_freq == 60) {
222319a81c14SSteve Longerbeam 		/* 60Hz */
222419a81c14SSteve Longerbeam 		cap_bandfilt = cap_sysclk * 100 / cap_hts * 100 / 120;
222519a81c14SSteve Longerbeam 	} else {
222619a81c14SSteve Longerbeam 		/* 50Hz */
222719a81c14SSteve Longerbeam 		cap_bandfilt = cap_sysclk * 100 / cap_hts;
222819a81c14SSteve Longerbeam 	}
222919a81c14SSteve Longerbeam 
223019a81c14SSteve Longerbeam 	if (!sensor->prev_sysclk) {
223119a81c14SSteve Longerbeam 		ret = ov5640_get_sysclk(sensor);
223219a81c14SSteve Longerbeam 		if (ret < 0)
223319a81c14SSteve Longerbeam 			return ret;
223419a81c14SSteve Longerbeam 		if (ret == 0)
223519a81c14SSteve Longerbeam 			return -EINVAL;
223619a81c14SSteve Longerbeam 		sensor->prev_sysclk = ret;
223719a81c14SSteve Longerbeam 	}
223819a81c14SSteve Longerbeam 
223919a81c14SSteve Longerbeam 	if (!cap_bandfilt)
224019a81c14SSteve Longerbeam 		return -EINVAL;
224119a81c14SSteve Longerbeam 
224219a81c14SSteve Longerbeam 	cap_maxband = (int)((cap_vts - 4) / cap_bandfilt);
224319a81c14SSteve Longerbeam 
224419a81c14SSteve Longerbeam 	/* calculate capture shutter/gain16 */
224519a81c14SSteve Longerbeam 	if (average > sensor->ae_low && average < sensor->ae_high) {
224619a81c14SSteve Longerbeam 		/* in stable range */
224719a81c14SSteve Longerbeam 		cap_gain16_shutter =
224819a81c14SSteve Longerbeam 			prev_gain16 * prev_shutter *
224919a81c14SSteve Longerbeam 			cap_sysclk / sensor->prev_sysclk *
225019a81c14SSteve Longerbeam 			sensor->prev_hts / cap_hts *
225119a81c14SSteve Longerbeam 			sensor->ae_target / average;
225219a81c14SSteve Longerbeam 	} else {
225319a81c14SSteve Longerbeam 		cap_gain16_shutter =
225419a81c14SSteve Longerbeam 			prev_gain16 * prev_shutter *
225519a81c14SSteve Longerbeam 			cap_sysclk / sensor->prev_sysclk *
225619a81c14SSteve Longerbeam 			sensor->prev_hts / cap_hts;
225719a81c14SSteve Longerbeam 	}
225819a81c14SSteve Longerbeam 
225919a81c14SSteve Longerbeam 	/* gain to shutter */
226019a81c14SSteve Longerbeam 	if (cap_gain16_shutter < (cap_bandfilt * 16)) {
226119a81c14SSteve Longerbeam 		/* shutter < 1/100 */
226219a81c14SSteve Longerbeam 		cap_shutter = cap_gain16_shutter / 16;
226319a81c14SSteve Longerbeam 		if (cap_shutter < 1)
226419a81c14SSteve Longerbeam 			cap_shutter = 1;
226519a81c14SSteve Longerbeam 
226619a81c14SSteve Longerbeam 		cap_gain16 = cap_gain16_shutter / cap_shutter;
226719a81c14SSteve Longerbeam 		if (cap_gain16 < 16)
226819a81c14SSteve Longerbeam 			cap_gain16 = 16;
226919a81c14SSteve Longerbeam 	} else {
227019a81c14SSteve Longerbeam 		if (cap_gain16_shutter > (cap_bandfilt * cap_maxband * 16)) {
227119a81c14SSteve Longerbeam 			/* exposure reach max */
227219a81c14SSteve Longerbeam 			cap_shutter = cap_bandfilt * cap_maxband;
227319a81c14SSteve Longerbeam 			if (!cap_shutter)
227419a81c14SSteve Longerbeam 				return -EINVAL;
227519a81c14SSteve Longerbeam 
227619a81c14SSteve Longerbeam 			cap_gain16 = cap_gain16_shutter / cap_shutter;
227719a81c14SSteve Longerbeam 		} else {
227819a81c14SSteve Longerbeam 			/* 1/100 < (cap_shutter = n/100) =< max */
227919a81c14SSteve Longerbeam 			cap_shutter =
228019a81c14SSteve Longerbeam 				((int)(cap_gain16_shutter / 16 / cap_bandfilt))
228119a81c14SSteve Longerbeam 				* cap_bandfilt;
228219a81c14SSteve Longerbeam 			if (!cap_shutter)
228319a81c14SSteve Longerbeam 				return -EINVAL;
228419a81c14SSteve Longerbeam 
228519a81c14SSteve Longerbeam 			cap_gain16 = cap_gain16_shutter / cap_shutter;
228619a81c14SSteve Longerbeam 		}
228719a81c14SSteve Longerbeam 	}
228819a81c14SSteve Longerbeam 
228919a81c14SSteve Longerbeam 	/* set capture gain */
22903cca8ef5SHugues Fruchet 	ret = ov5640_set_gain(sensor, cap_gain16);
229119a81c14SSteve Longerbeam 	if (ret)
229219a81c14SSteve Longerbeam 		return ret;
229319a81c14SSteve Longerbeam 
229419a81c14SSteve Longerbeam 	/* write capture shutter */
229519a81c14SSteve Longerbeam 	if (cap_shutter > (cap_vts - 4)) {
229619a81c14SSteve Longerbeam 		cap_vts = cap_shutter + 4;
229719a81c14SSteve Longerbeam 		ret = ov5640_set_vts(sensor, cap_vts);
229819a81c14SSteve Longerbeam 		if (ret < 0)
229919a81c14SSteve Longerbeam 			return ret;
230019a81c14SSteve Longerbeam 	}
230119a81c14SSteve Longerbeam 
230219a81c14SSteve Longerbeam 	/* set exposure */
23033cca8ef5SHugues Fruchet 	return ov5640_set_exposure(sensor, cap_shutter);
230419a81c14SSteve Longerbeam }
230519a81c14SSteve Longerbeam 
230619a81c14SSteve Longerbeam /*
230719a81c14SSteve Longerbeam  * if sensor changes inside scaling or subsampling
230819a81c14SSteve Longerbeam  * change mode directly
230919a81c14SSteve Longerbeam  */
231019a81c14SSteve Longerbeam static int ov5640_set_mode_direct(struct ov5640_dev *sensor,
23113cca8ef5SHugues Fruchet 				  const struct ov5640_mode_info *mode)
231219a81c14SSteve Longerbeam {
231341d8d7f5SHugues Fruchet 	if (!mode->reg_data)
231419a81c14SSteve Longerbeam 		return -EINVAL;
231519a81c14SSteve Longerbeam 
231619a81c14SSteve Longerbeam 	/* Write capture setting */
2317e4359019SJacopo Mondi 	ov5640_load_regs(sensor, mode->reg_data, mode->reg_data_size);
2318e4359019SJacopo Mondi 	return ov5640_set_timings(sensor, mode);
231919a81c14SSteve Longerbeam }
232019a81c14SSteve Longerbeam 
2321985cdcb0SHugues Fruchet static int ov5640_set_mode(struct ov5640_dev *sensor)
232219a81c14SSteve Longerbeam {
232319a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode = sensor->current_mode;
2324985cdcb0SHugues Fruchet 	const struct ov5640_mode_info *orig_mode = sensor->last_mode;
232519a81c14SSteve Longerbeam 	enum ov5640_downsize_mode dn_mode, orig_dn_mode;
23263cca8ef5SHugues Fruchet 	bool auto_gain = sensor->ctrls.auto_gain->val == 1;
2327dc29a1c1SHugues Fruchet 	bool auto_exp =  sensor->ctrls.auto_exp->val == V4L2_EXPOSURE_AUTO;
232819a81c14SSteve Longerbeam 	int ret;
232919a81c14SSteve Longerbeam 
233019a81c14SSteve Longerbeam 	dn_mode = mode->dn_mode;
233119a81c14SSteve Longerbeam 	orig_dn_mode = orig_mode->dn_mode;
233219a81c14SSteve Longerbeam 
233319a81c14SSteve Longerbeam 	/* auto gain and exposure must be turned off when changing modes */
23343cca8ef5SHugues Fruchet 	if (auto_gain) {
23353cca8ef5SHugues Fruchet 		ret = ov5640_set_autogain(sensor, false);
233619a81c14SSteve Longerbeam 		if (ret)
233719a81c14SSteve Longerbeam 			return ret;
23383cca8ef5SHugues Fruchet 	}
2339bf4a4b51SMaxime Ripard 
23403cca8ef5SHugues Fruchet 	if (auto_exp) {
2341dc29a1c1SHugues Fruchet 		ret = ov5640_set_autoexposure(sensor, false);
234219a81c14SSteve Longerbeam 		if (ret)
23433cca8ef5SHugues Fruchet 			goto restore_auto_gain;
23443cca8ef5SHugues Fruchet 	}
234519a81c14SSteve Longerbeam 
23466c957ed7SJacopo Mondi 	if (ov5640_is_csi2(sensor))
23476c957ed7SJacopo Mondi 		ret = ov5640_set_mipi_pclk(sensor);
23486c957ed7SJacopo Mondi 	else
23496c957ed7SJacopo Mondi 		ret = ov5640_set_dvp_pclk(sensor);
2350aa288248SMaxime Ripard 	if (ret < 0)
2351aa288248SMaxime Ripard 		return 0;
2352aa288248SMaxime Ripard 
235319a81c14SSteve Longerbeam 	if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) ||
235419a81c14SSteve Longerbeam 	    (dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) {
235519a81c14SSteve Longerbeam 		/*
235619a81c14SSteve Longerbeam 		 * change between subsampling and scaling
23573cca8ef5SHugues Fruchet 		 * go through exposure calculation
235819a81c14SSteve Longerbeam 		 */
235919a81c14SSteve Longerbeam 		ret = ov5640_set_mode_exposure_calc(sensor, mode);
236019a81c14SSteve Longerbeam 	} else {
236119a81c14SSteve Longerbeam 		/*
236219a81c14SSteve Longerbeam 		 * change inside subsampling or scaling
236319a81c14SSteve Longerbeam 		 * download firmware directly
236419a81c14SSteve Longerbeam 		 */
23653cca8ef5SHugues Fruchet 		ret = ov5640_set_mode_direct(sensor, mode);
236619a81c14SSteve Longerbeam 	}
236719a81c14SSteve Longerbeam 	if (ret < 0)
23683cca8ef5SHugues Fruchet 		goto restore_auto_exp_gain;
23693cca8ef5SHugues Fruchet 
23703cca8ef5SHugues Fruchet 	/* restore auto gain and exposure */
23713cca8ef5SHugues Fruchet 	if (auto_gain)
23723cca8ef5SHugues Fruchet 		ov5640_set_autogain(sensor, true);
23733cca8ef5SHugues Fruchet 	if (auto_exp)
23743cca8ef5SHugues Fruchet 		ov5640_set_autoexposure(sensor, true);
237519a81c14SSteve Longerbeam 
2376ce85705aSHugues Fruchet 	ret = ov5640_set_binning(sensor, dn_mode != SCALING);
2377ce85705aSHugues Fruchet 	if (ret < 0)
2378ce85705aSHugues Fruchet 		return ret;
237919a81c14SSteve Longerbeam 	ret = ov5640_set_ae_target(sensor, sensor->ae_target);
238019a81c14SSteve Longerbeam 	if (ret < 0)
238119a81c14SSteve Longerbeam 		return ret;
238219a81c14SSteve Longerbeam 	ret = ov5640_get_light_freq(sensor);
238319a81c14SSteve Longerbeam 	if (ret < 0)
238419a81c14SSteve Longerbeam 		return ret;
238519a81c14SSteve Longerbeam 	ret = ov5640_set_bandingfilter(sensor);
238619a81c14SSteve Longerbeam 	if (ret < 0)
238719a81c14SSteve Longerbeam 		return ret;
238819a81c14SSteve Longerbeam 	ret = ov5640_set_virtual_channel(sensor);
238919a81c14SSteve Longerbeam 	if (ret < 0)
239019a81c14SSteve Longerbeam 		return ret;
239119a81c14SSteve Longerbeam 
239219a81c14SSteve Longerbeam 	sensor->pending_mode_change = false;
2393985cdcb0SHugues Fruchet 	sensor->last_mode = mode;
239419a81c14SSteve Longerbeam 
239519a81c14SSteve Longerbeam 	return 0;
23963cca8ef5SHugues Fruchet 
23973cca8ef5SHugues Fruchet restore_auto_exp_gain:
23983cca8ef5SHugues Fruchet 	if (auto_exp)
23993cca8ef5SHugues Fruchet 		ov5640_set_autoexposure(sensor, true);
24003cca8ef5SHugues Fruchet restore_auto_gain:
24013cca8ef5SHugues Fruchet 	if (auto_gain)
24023cca8ef5SHugues Fruchet 		ov5640_set_autogain(sensor, true);
24033cca8ef5SHugues Fruchet 
24043cca8ef5SHugues Fruchet 	return ret;
240519a81c14SSteve Longerbeam }
240619a81c14SSteve Longerbeam 
240719ad26f9SAkinobu Mita static int ov5640_set_framefmt(struct ov5640_dev *sensor,
240819ad26f9SAkinobu Mita 			       struct v4l2_mbus_framefmt *format);
240919ad26f9SAkinobu Mita 
241019a81c14SSteve Longerbeam /* restore the last set video mode after chip power-on */
241119a81c14SSteve Longerbeam static int ov5640_restore_mode(struct ov5640_dev *sensor)
241219a81c14SSteve Longerbeam {
241319a81c14SSteve Longerbeam 	int ret;
241419a81c14SSteve Longerbeam 
241519a81c14SSteve Longerbeam 	/* first load the initial register values */
2416e4359019SJacopo Mondi 	ov5640_load_regs(sensor, ov5640_init_setting,
2417e4359019SJacopo Mondi 			 ARRAY_SIZE(ov5640_init_setting));
241819a81c14SSteve Longerbeam 
24198f57c2f8SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
24207851fe7aSMaxime Ripard 			     (ilog2(OV5640_SCLK2X_ROOT_DIV) << 2) |
24217851fe7aSMaxime Ripard 			     ilog2(OV5640_SCLK_ROOT_DIV));
24228f57c2f8SMaxime Ripard 	if (ret)
24238f57c2f8SMaxime Ripard 		return ret;
24248f57c2f8SMaxime Ripard 
242519a81c14SSteve Longerbeam 	/* now restore the last capture mode */
2426985cdcb0SHugues Fruchet 	ret = ov5640_set_mode(sensor);
242719ad26f9SAkinobu Mita 	if (ret < 0)
242819ad26f9SAkinobu Mita 		return ret;
242919ad26f9SAkinobu Mita 
243019ad26f9SAkinobu Mita 	return ov5640_set_framefmt(sensor, &sensor->fmt);
243119a81c14SSteve Longerbeam }
243219a81c14SSteve Longerbeam 
243319a81c14SSteve Longerbeam static void ov5640_power(struct ov5640_dev *sensor, bool enable)
243419a81c14SSteve Longerbeam {
24351fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->pwdn_gpio, enable ? 0 : 1);
243619a81c14SSteve Longerbeam }
243719a81c14SSteve Longerbeam 
243819a81c14SSteve Longerbeam static void ov5640_reset(struct ov5640_dev *sensor)
243919a81c14SSteve Longerbeam {
244019a81c14SSteve Longerbeam 	if (!sensor->reset_gpio)
244119a81c14SSteve Longerbeam 		return;
244219a81c14SSteve Longerbeam 
24431fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 0);
244419a81c14SSteve Longerbeam 
244519a81c14SSteve Longerbeam 	/* camera power cycle */
244619a81c14SSteve Longerbeam 	ov5640_power(sensor, false);
244719a81c14SSteve Longerbeam 	usleep_range(5000, 10000);
244819a81c14SSteve Longerbeam 	ov5640_power(sensor, true);
244919a81c14SSteve Longerbeam 	usleep_range(5000, 10000);
245019a81c14SSteve Longerbeam 
24511fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 1);
245219a81c14SSteve Longerbeam 	usleep_range(1000, 2000);
245319a81c14SSteve Longerbeam 
24541fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 0);
24551d4c41f3SLoic Poulain 	usleep_range(20000, 25000);
245619a81c14SSteve Longerbeam }
245719a81c14SSteve Longerbeam 
24580f7acb52SHugues Fruchet static int ov5640_set_power_on(struct ov5640_dev *sensor)
245919a81c14SSteve Longerbeam {
24600f7acb52SHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
24610f7acb52SHugues Fruchet 	int ret;
246219a81c14SSteve Longerbeam 
24630f7acb52SHugues Fruchet 	ret = clk_prepare_enable(sensor->xclk);
24640f7acb52SHugues Fruchet 	if (ret) {
24650f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to enable clock\n",
24660f7acb52SHugues Fruchet 			__func__);
24670f7acb52SHugues Fruchet 		return ret;
24680f7acb52SHugues Fruchet 	}
246919a81c14SSteve Longerbeam 
247019a81c14SSteve Longerbeam 	ret = regulator_bulk_enable(OV5640_NUM_SUPPLIES,
247119a81c14SSteve Longerbeam 				    sensor->supplies);
24720f7acb52SHugues Fruchet 	if (ret) {
24730f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to enable regulators\n",
24740f7acb52SHugues Fruchet 			__func__);
247519a81c14SSteve Longerbeam 		goto xclk_off;
24760f7acb52SHugues Fruchet 	}
247719a81c14SSteve Longerbeam 
247819a81c14SSteve Longerbeam 	ov5640_reset(sensor);
247919a81c14SSteve Longerbeam 	ov5640_power(sensor, true);
248019a81c14SSteve Longerbeam 
248119a81c14SSteve Longerbeam 	ret = ov5640_init_slave_id(sensor);
248219a81c14SSteve Longerbeam 	if (ret)
248319a81c14SSteve Longerbeam 		goto power_off;
248419a81c14SSteve Longerbeam 
24850f7acb52SHugues Fruchet 	return 0;
24860f7acb52SHugues Fruchet 
24870f7acb52SHugues Fruchet power_off:
24880f7acb52SHugues Fruchet 	ov5640_power(sensor, false);
24890f7acb52SHugues Fruchet 	regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies);
24900f7acb52SHugues Fruchet xclk_off:
24910f7acb52SHugues Fruchet 	clk_disable_unprepare(sensor->xclk);
24920f7acb52SHugues Fruchet 	return ret;
24930f7acb52SHugues Fruchet }
24940f7acb52SHugues Fruchet 
24950f7acb52SHugues Fruchet static void ov5640_set_power_off(struct ov5640_dev *sensor)
24960f7acb52SHugues Fruchet {
24970f7acb52SHugues Fruchet 	ov5640_power(sensor, false);
24980f7acb52SHugues Fruchet 	regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies);
24990f7acb52SHugues Fruchet 	clk_disable_unprepare(sensor->xclk);
25000f7acb52SHugues Fruchet }
25010f7acb52SHugues Fruchet 
2502b1751ae6SLad Prabhakar static int ov5640_set_power_mipi(struct ov5640_dev *sensor, bool on)
2503b1751ae6SLad Prabhakar {
2504b1751ae6SLad Prabhakar 	int ret;
2505b1751ae6SLad Prabhakar 
2506b1751ae6SLad Prabhakar 	if (!on) {
2507b1751ae6SLad Prabhakar 		/* Reset MIPI bus settings to their default values. */
2508b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
2509b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x04);
2510b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x00);
2511b1751ae6SLad Prabhakar 		return 0;
2512b1751ae6SLad Prabhakar 	}
2513b1751ae6SLad Prabhakar 
2514b1751ae6SLad Prabhakar 	/*
2515b1751ae6SLad Prabhakar 	 * Power up MIPI HS Tx and LS Rx; 2 data lanes mode
2516b1751ae6SLad Prabhakar 	 *
2517b1751ae6SLad Prabhakar 	 * 0x300e = 0x40
2518b1751ae6SLad Prabhakar 	 * [7:5] = 010	: 2 data lanes mode (see FIXME note in
2519b1751ae6SLad Prabhakar 	 *		  "ov5640_set_stream_mipi()")
2520b1751ae6SLad Prabhakar 	 * [4] = 0	: Power up MIPI HS Tx
2521b1751ae6SLad Prabhakar 	 * [3] = 0	: Power up MIPI LS Rx
2522b1751ae6SLad Prabhakar 	 * [2] = 0	: MIPI interface disabled
2523b1751ae6SLad Prabhakar 	 */
2524b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x40);
2525b1751ae6SLad Prabhakar 	if (ret)
2526b1751ae6SLad Prabhakar 		return ret;
2527b1751ae6SLad Prabhakar 
2528b1751ae6SLad Prabhakar 	/*
2529b1751ae6SLad Prabhakar 	 * Gate clock and set LP11 in 'no packets mode' (idle)
2530b1751ae6SLad Prabhakar 	 *
2531b1751ae6SLad Prabhakar 	 * 0x4800 = 0x24
2532b1751ae6SLad Prabhakar 	 * [5] = 1	: Gate clock when 'no packets'
2533b1751ae6SLad Prabhakar 	 * [2] = 1	: MIPI bus in LP11 when 'no packets'
2534b1751ae6SLad Prabhakar 	 */
2535b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x24);
2536b1751ae6SLad Prabhakar 	if (ret)
2537b1751ae6SLad Prabhakar 		return ret;
2538b1751ae6SLad Prabhakar 
2539b1751ae6SLad Prabhakar 	/*
2540b1751ae6SLad Prabhakar 	 * Set data lanes and clock in LP11 when 'sleeping'
2541b1751ae6SLad Prabhakar 	 *
2542b1751ae6SLad Prabhakar 	 * 0x3019 = 0x70
2543b1751ae6SLad Prabhakar 	 * [6] = 1	: MIPI data lane 2 in LP11 when 'sleeping'
2544b1751ae6SLad Prabhakar 	 * [5] = 1	: MIPI data lane 1 in LP11 when 'sleeping'
2545b1751ae6SLad Prabhakar 	 * [4] = 1	: MIPI clock lane in LP11 when 'sleeping'
2546b1751ae6SLad Prabhakar 	 */
2547b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x70);
2548b1751ae6SLad Prabhakar 	if (ret)
2549b1751ae6SLad Prabhakar 		return ret;
2550b1751ae6SLad Prabhakar 
2551b1751ae6SLad Prabhakar 	/* Give lanes some time to coax into LP11 state. */
2552b1751ae6SLad Prabhakar 	usleep_range(500, 1000);
2553b1751ae6SLad Prabhakar 
2554b1751ae6SLad Prabhakar 	return 0;
2555b1751ae6SLad Prabhakar }
2556b1751ae6SLad Prabhakar 
2557576f5d4bSLad Prabhakar static int ov5640_set_power_dvp(struct ov5640_dev *sensor, bool on)
2558576f5d4bSLad Prabhakar {
2559311a6408SLad Prabhakar 	unsigned int flags = sensor->ep.bus.parallel.flags;
256068579b32SHugues Fruchet 	bool bt656 = sensor->ep.bus_type == V4L2_MBUS_BT656;
256168579b32SHugues Fruchet 	u8 polarities = 0;
2562576f5d4bSLad Prabhakar 	int ret;
2563576f5d4bSLad Prabhakar 
2564576f5d4bSLad Prabhakar 	if (!on) {
2565576f5d4bSLad Prabhakar 		/* Reset settings to their default values. */
256668579b32SHugues Fruchet 		ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00, 0x00);
2567311a6408SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
2568311a6408SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, 0x20);
2569576f5d4bSLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01, 0x00);
2570576f5d4bSLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0x00);
2571576f5d4bSLad Prabhakar 		return 0;
2572576f5d4bSLad Prabhakar 	}
2573576f5d4bSLad Prabhakar 
2574576f5d4bSLad Prabhakar 	/*
2575311a6408SLad Prabhakar 	 * Note about parallel port configuration.
2576311a6408SLad Prabhakar 	 *
2577311a6408SLad Prabhakar 	 * When configured in parallel mode, the OV5640 will
2578311a6408SLad Prabhakar 	 * output 10 bits data on DVP data lines [9:0].
2579311a6408SLad Prabhakar 	 * If only 8 bits data are wanted, the 8 bits data lines
2580311a6408SLad Prabhakar 	 * of the camera interface must be physically connected
2581311a6408SLad Prabhakar 	 * on the DVP data lines [9:2].
2582311a6408SLad Prabhakar 	 *
2583311a6408SLad Prabhakar 	 * Control lines polarity can be configured through
2584311a6408SLad Prabhakar 	 * devicetree endpoint control lines properties.
2585311a6408SLad Prabhakar 	 * If no endpoint control lines properties are set,
2586311a6408SLad Prabhakar 	 * polarity will be as below:
2587311a6408SLad Prabhakar 	 * - VSYNC:	active high
2588311a6408SLad Prabhakar 	 * - HREF:	active low
2589311a6408SLad Prabhakar 	 * - PCLK:	active low
259068579b32SHugues Fruchet 	 *
259168579b32SHugues Fruchet 	 * VSYNC & HREF are not configured if BT656 bus mode is selected
2592311a6408SLad Prabhakar 	 */
259368579b32SHugues Fruchet 
259468579b32SHugues Fruchet 	/*
259568579b32SHugues Fruchet 	 * BT656 embedded synchronization configuration
259668579b32SHugues Fruchet 	 *
259768579b32SHugues Fruchet 	 * CCIR656 CTRL00
259868579b32SHugues Fruchet 	 * - [7]:	SYNC code selection (0: auto generate sync code,
259968579b32SHugues Fruchet 	 *		1: sync code from regs 0x4732-0x4735)
260068579b32SHugues Fruchet 	 * - [6]:	f value in CCIR656 SYNC code when fixed f value
260168579b32SHugues Fruchet 	 * - [5]:	Fixed f value
260268579b32SHugues Fruchet 	 * - [4:3]:	Blank toggle data options (00: data=1'h040/1'h200,
260368579b32SHugues Fruchet 	 *		01: data from regs 0x4736-0x4738, 10: always keep 0)
260468579b32SHugues Fruchet 	 * - [1]:	Clip data disable
260568579b32SHugues Fruchet 	 * - [0]:	CCIR656 mode enable
260668579b32SHugues Fruchet 	 *
260768579b32SHugues Fruchet 	 * Default CCIR656 SAV/EAV mode with default codes
260868579b32SHugues Fruchet 	 * SAV=0xff000080 & EAV=0xff00009d is enabled here with settings:
260968579b32SHugues Fruchet 	 * - CCIR656 mode enable
261068579b32SHugues Fruchet 	 * - auto generation of sync codes
261168579b32SHugues Fruchet 	 * - blank toggle data 1'h040/1'h200
261268579b32SHugues Fruchet 	 * - clip reserved data (0x00 & 0xff changed to 0x01 & 0xfe)
261368579b32SHugues Fruchet 	 */
261468579b32SHugues Fruchet 	ret = ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00,
261568579b32SHugues Fruchet 			       bt656 ? 0x01 : 0x00);
261668579b32SHugues Fruchet 	if (ret)
261768579b32SHugues Fruchet 		return ret;
261868579b32SHugues Fruchet 
2619311a6408SLad Prabhakar 	/*
2620311a6408SLad Prabhakar 	 * configure parallel port control lines polarity
2621311a6408SLad Prabhakar 	 *
2622311a6408SLad Prabhakar 	 * POLARITY CTRL0
2623311a6408SLad Prabhakar 	 * - [5]:	PCLK polarity (0: active low, 1: active high)
2624311a6408SLad Prabhakar 	 * - [1]:	HREF polarity (0: active low, 1: active high)
2625311a6408SLad Prabhakar 	 * - [0]:	VSYNC polarity (mismatch here between
2626311a6408SLad Prabhakar 	 *		datasheet and hardware, 0 is active high
2627311a6408SLad Prabhakar 	 *		and 1 is active low...)
2628311a6408SLad Prabhakar 	 */
262968579b32SHugues Fruchet 	if (!bt656) {
2630311a6408SLad Prabhakar 		if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
263168579b32SHugues Fruchet 			polarities |= BIT(1);
2632311a6408SLad Prabhakar 		if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
263368579b32SHugues Fruchet 			polarities |= BIT(0);
263468579b32SHugues Fruchet 	}
263568579b32SHugues Fruchet 	if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
263668579b32SHugues Fruchet 		polarities |= BIT(5);
2637311a6408SLad Prabhakar 
263868579b32SHugues Fruchet 	ret = ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, polarities);
2639311a6408SLad Prabhakar 	if (ret)
2640311a6408SLad Prabhakar 		return ret;
2641311a6408SLad Prabhakar 
2642311a6408SLad Prabhakar 	/*
264368579b32SHugues Fruchet 	 * powerdown MIPI TX/RX PHY & enable DVP
2644311a6408SLad Prabhakar 	 *
2645311a6408SLad Prabhakar 	 * MIPI CONTROL 00
264668579b32SHugues Fruchet 	 * [4] = 1	: Power down MIPI HS Tx
264768579b32SHugues Fruchet 	 * [3] = 1	: Power down MIPI LS Rx
264868579b32SHugues Fruchet 	 * [2] = 0	: DVP enable (MIPI disable)
2649311a6408SLad Prabhakar 	 */
2650311a6408SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x18);
2651311a6408SLad Prabhakar 	if (ret)
2652311a6408SLad Prabhakar 		return ret;
2653311a6408SLad Prabhakar 
2654311a6408SLad Prabhakar 	/*
2655576f5d4bSLad Prabhakar 	 * enable VSYNC/HREF/PCLK DVP control lines
2656576f5d4bSLad Prabhakar 	 * & D[9:6] DVP data lines
2657576f5d4bSLad Prabhakar 	 *
2658576f5d4bSLad Prabhakar 	 * PAD OUTPUT ENABLE 01
2659576f5d4bSLad Prabhakar 	 * - 6:		VSYNC output enable
2660576f5d4bSLad Prabhakar 	 * - 5:		HREF output enable
2661576f5d4bSLad Prabhakar 	 * - 4:		PCLK output enable
2662576f5d4bSLad Prabhakar 	 * - [3:0]:	D[9:6] output enable
2663576f5d4bSLad Prabhakar 	 */
26644039b037SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01,
266568579b32SHugues Fruchet 			       bt656 ? 0x1f : 0x7f);
2666576f5d4bSLad Prabhakar 	if (ret)
2667576f5d4bSLad Prabhakar 		return ret;
2668576f5d4bSLad Prabhakar 
2669576f5d4bSLad Prabhakar 	/*
2670576f5d4bSLad Prabhakar 	 * enable D[5:0] DVP data lines
2671576f5d4bSLad Prabhakar 	 *
2672576f5d4bSLad Prabhakar 	 * PAD OUTPUT ENABLE 02
2673576f5d4bSLad Prabhakar 	 * - [7:2]:	D[5:0] output enable
2674576f5d4bSLad Prabhakar 	 */
2675576f5d4bSLad Prabhakar 	return ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0xfc);
2676576f5d4bSLad Prabhakar }
2677576f5d4bSLad Prabhakar 
26780f7acb52SHugues Fruchet static int ov5640_set_power(struct ov5640_dev *sensor, bool on)
26790f7acb52SHugues Fruchet {
26800f7acb52SHugues Fruchet 	int ret = 0;
26810f7acb52SHugues Fruchet 
26820f7acb52SHugues Fruchet 	if (on) {
26830f7acb52SHugues Fruchet 		ret = ov5640_set_power_on(sensor);
26840f7acb52SHugues Fruchet 		if (ret)
26850f7acb52SHugues Fruchet 			return ret;
26860f7acb52SHugues Fruchet 
268719a81c14SSteve Longerbeam 		ret = ov5640_restore_mode(sensor);
268819a81c14SSteve Longerbeam 		if (ret)
268919a81c14SSteve Longerbeam 			goto power_off;
2690b1751ae6SLad Prabhakar 	}
269119a81c14SSteve Longerbeam 
2692576f5d4bSLad Prabhakar 	if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY)
2693b1751ae6SLad Prabhakar 		ret = ov5640_set_power_mipi(sensor, on);
2694576f5d4bSLad Prabhakar 	else
2695576f5d4bSLad Prabhakar 		ret = ov5640_set_power_dvp(sensor, on);
2696b1751ae6SLad Prabhakar 	if (ret)
2697b1751ae6SLad Prabhakar 		goto power_off;
2698aa4bb8b8SJacopo Mondi 
2699b1751ae6SLad Prabhakar 	if (!on)
2700aa4bb8b8SJacopo Mondi 		ov5640_set_power_off(sensor);
270119a81c14SSteve Longerbeam 
270219a81c14SSteve Longerbeam 	return 0;
270319a81c14SSteve Longerbeam 
270419a81c14SSteve Longerbeam power_off:
27050f7acb52SHugues Fruchet 	ov5640_set_power_off(sensor);
270619a81c14SSteve Longerbeam 	return ret;
270719a81c14SSteve Longerbeam }
270819a81c14SSteve Longerbeam 
270985644a9bSPaul Elder static int ov5640_sensor_suspend(struct device *dev)
271019a81c14SSteve Longerbeam {
271185644a9bSPaul Elder 	struct v4l2_subdev *sd = dev_get_drvdata(dev);
271285644a9bSPaul Elder 	struct ov5640_dev *ov5640 = to_ov5640_dev(sd);
271319a81c14SSteve Longerbeam 
271485644a9bSPaul Elder 	return ov5640_set_power(ov5640, false);
271519a81c14SSteve Longerbeam }
271619a81c14SSteve Longerbeam 
271785644a9bSPaul Elder static int ov5640_sensor_resume(struct device *dev)
271885644a9bSPaul Elder {
271985644a9bSPaul Elder 	struct v4l2_subdev *sd = dev_get_drvdata(dev);
272085644a9bSPaul Elder 	struct ov5640_dev *ov5640 = to_ov5640_dev(sd);
272119a81c14SSteve Longerbeam 
272285644a9bSPaul Elder 	return ov5640_set_power(ov5640, true);
272319a81c14SSteve Longerbeam }
272419a81c14SSteve Longerbeam 
272585644a9bSPaul Elder /* --------------- Subdev Operations --------------- */
272619a81c14SSteve Longerbeam 
272719a81c14SSteve Longerbeam static int ov5640_try_frame_interval(struct ov5640_dev *sensor,
272819a81c14SSteve Longerbeam 				     struct v4l2_fract *fi,
2729f33b56d3SGuoniu.zhou 				     const struct ov5640_mode_info *mode_info)
273019a81c14SSteve Longerbeam {
2731f33b56d3SGuoniu.zhou 	const struct ov5640_mode_info *mode = mode_info;
27326530a5ebSJagan Teki 	enum ov5640_frame_rate rate = OV5640_15_FPS;
2733f6cc192fSMaxime Ripard 	int minfps, maxfps, best_fps, fps;
2734f6cc192fSMaxime Ripard 	int i;
273519a81c14SSteve Longerbeam 
273619a81c14SSteve Longerbeam 	minfps = ov5640_framerates[OV5640_15_FPS];
2737f33b56d3SGuoniu.zhou 	maxfps = ov5640_framerates[mode->max_fps];
273819a81c14SSteve Longerbeam 
273919a81c14SSteve Longerbeam 	if (fi->numerator == 0) {
274019a81c14SSteve Longerbeam 		fi->denominator = maxfps;
274119a81c14SSteve Longerbeam 		fi->numerator = 1;
2742f33b56d3SGuoniu.zhou 		rate = mode->max_fps;
2743e823fb16SMaxime Ripard 		goto find_mode;
274419a81c14SSteve Longerbeam 	}
274519a81c14SSteve Longerbeam 
2746f6cc192fSMaxime Ripard 	fps = clamp_val(DIV_ROUND_CLOSEST(fi->denominator, fi->numerator),
2747f6cc192fSMaxime Ripard 			minfps, maxfps);
2748f6cc192fSMaxime Ripard 
2749f6cc192fSMaxime Ripard 	best_fps = minfps;
2750f6cc192fSMaxime Ripard 	for (i = 0; i < ARRAY_SIZE(ov5640_framerates); i++) {
2751f6cc192fSMaxime Ripard 		int curr_fps = ov5640_framerates[i];
2752f6cc192fSMaxime Ripard 
2753f6cc192fSMaxime Ripard 		if (abs(curr_fps - fps) < abs(best_fps - fps)) {
2754f6cc192fSMaxime Ripard 			best_fps = curr_fps;
2755f6cc192fSMaxime Ripard 			rate = i;
2756f6cc192fSMaxime Ripard 		}
2757f6cc192fSMaxime Ripard 	}
275819a81c14SSteve Longerbeam 
275919a81c14SSteve Longerbeam 	fi->numerator = 1;
2760f6cc192fSMaxime Ripard 	fi->denominator = best_fps;
276119a81c14SSteve Longerbeam 
2762e823fb16SMaxime Ripard find_mode:
2763f33b56d3SGuoniu.zhou 	mode = ov5640_find_mode(sensor, mode->width, mode->height, false);
27645a3ad937SMaxime Ripard 	return mode ? rate : -EINVAL;
276519a81c14SSteve Longerbeam }
276619a81c14SSteve Longerbeam 
276719a81c14SSteve Longerbeam static int ov5640_get_fmt(struct v4l2_subdev *sd,
27680d346d2aSTomi Valkeinen 			  struct v4l2_subdev_state *sd_state,
276919a81c14SSteve Longerbeam 			  struct v4l2_subdev_format *format)
277019a81c14SSteve Longerbeam {
277119a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
277219a81c14SSteve Longerbeam 	struct v4l2_mbus_framefmt *fmt;
277319a81c14SSteve Longerbeam 
277419a81c14SSteve Longerbeam 	if (format->pad != 0)
277519a81c14SSteve Longerbeam 		return -EINVAL;
277619a81c14SSteve Longerbeam 
277719a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
277819a81c14SSteve Longerbeam 
277919a81c14SSteve Longerbeam 	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
27800d346d2aSTomi Valkeinen 		fmt = v4l2_subdev_get_try_format(&sensor->sd, sd_state,
278119a81c14SSteve Longerbeam 						 format->pad);
278219a81c14SSteve Longerbeam 	else
278319a81c14SSteve Longerbeam 		fmt = &sensor->fmt;
278419a81c14SSteve Longerbeam 
278519a81c14SSteve Longerbeam 	format->format = *fmt;
278619a81c14SSteve Longerbeam 
278719a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
278819a81c14SSteve Longerbeam 
278919a81c14SSteve Longerbeam 	return 0;
279019a81c14SSteve Longerbeam }
279119a81c14SSteve Longerbeam 
279219a81c14SSteve Longerbeam static int ov5640_try_fmt_internal(struct v4l2_subdev *sd,
279319a81c14SSteve Longerbeam 				   struct v4l2_mbus_framefmt *fmt,
279419a81c14SSteve Longerbeam 				   enum ov5640_frame_rate fr,
279519a81c14SSteve Longerbeam 				   const struct ov5640_mode_info **new_mode)
279619a81c14SSteve Longerbeam {
279719a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
279819a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
2799a89f14bbSJacopo Mondi 	const struct ov5640_pixfmt *pixfmt;
2800a89f14bbSJacopo Mondi 	unsigned int bpp;
280119a81c14SSteve Longerbeam 
2802b6ae5022SJacopo Mondi 	mode = ov5640_find_mode(sensor, fmt->width, fmt->height, true);
280319a81c14SSteve Longerbeam 	if (!mode)
280419a81c14SSteve Longerbeam 		return -EINVAL;
2805dd81b8ffSJacopo Mondi 
2806a89f14bbSJacopo Mondi 	pixfmt = ov5640_code_to_pixfmt(sensor, fmt->code);
2807a89f14bbSJacopo Mondi 	bpp = pixfmt->bpp;
2808a89f14bbSJacopo Mondi 
2809dd81b8ffSJacopo Mondi 	/*
2810dd81b8ffSJacopo Mondi 	 * Adjust mode according to bpp:
2811dd81b8ffSJacopo Mondi 	 * - 8bpp modes work for resolution >= 1280x720
2812dd81b8ffSJacopo Mondi 	 * - 24bpp modes work resolution < 1280x720
2813dd81b8ffSJacopo Mondi 	 */
2814dd81b8ffSJacopo Mondi 	if (bpp == 8 && mode->width < 1280)
2815dd81b8ffSJacopo Mondi 		mode = &ov5640_mode_data[OV5640_MODE_720P_1280_720];
2816dd81b8ffSJacopo Mondi 	else if (bpp == 24 && mode->width > 1024)
2817dd81b8ffSJacopo Mondi 		mode = &ov5640_mode_data[OV5640_MODE_XGA_1024_768];
2818dd81b8ffSJacopo Mondi 
28195113d5b3SJacopo Mondi 	fmt->width = mode->width;
28205113d5b3SJacopo Mondi 	fmt->height = mode->height;
282119a81c14SSteve Longerbeam 
282219a81c14SSteve Longerbeam 	if (new_mode)
282319a81c14SSteve Longerbeam 		*new_mode = mode;
2824e3ee691dSHugues Fruchet 
2825a89f14bbSJacopo Mondi 	fmt->code = pixfmt->code;
2826a89f14bbSJacopo Mondi 	fmt->colorspace = pixfmt->colorspace;
2827e6441fdeSHugues Fruchet 	fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
2828e6441fdeSHugues Fruchet 	fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
2829e6441fdeSHugues Fruchet 	fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
2830e3ee691dSHugues Fruchet 
283119a81c14SSteve Longerbeam 	return 0;
283219a81c14SSteve Longerbeam }
283319a81c14SSteve Longerbeam 
28343c28588fSJacopo Mondi static int ov5640_update_pixel_rate(struct ov5640_dev *sensor)
28353c28588fSJacopo Mondi {
28363c28588fSJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
28373c28588fSJacopo Mondi 	enum ov5640_pixel_rate_id pixel_rate_id = mode->pixel_rate;
28383c28588fSJacopo Mondi 	struct v4l2_mbus_framefmt *fmt = &sensor->fmt;
283932979f67SJacopo Mondi 	const struct ov5640_timings *timings;
2840bce93b82SJacopo Mondi 	s32 exposure_val, exposure_max;
284132979f67SJacopo Mondi 	unsigned int hblank;
28423c28588fSJacopo Mondi 	unsigned int i = 0;
28433c28588fSJacopo Mondi 	u32 pixel_rate;
28443c28588fSJacopo Mondi 	s64 link_freq;
28453c28588fSJacopo Mondi 	u32 num_lanes;
284619f2e3e6SHugues Fruchet 	u32 vblank;
28473c28588fSJacopo Mondi 	u32 bpp;
28483c28588fSJacopo Mondi 
28493c28588fSJacopo Mondi 	/*
28503c28588fSJacopo Mondi 	 * Update the pixel rate control value.
28513c28588fSJacopo Mondi 	 *
28523c28588fSJacopo Mondi 	 * For DVP mode, maintain the pixel rate calculation using fixed FPS.
28533c28588fSJacopo Mondi 	 */
28543c28588fSJacopo Mondi 	if (!ov5640_is_csi2(sensor)) {
28553c28588fSJacopo Mondi 		__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate,
28563c28588fSJacopo Mondi 					 ov5640_calc_pixel_rate(sensor));
28573c28588fSJacopo Mondi 
28583c28588fSJacopo Mondi 		return 0;
28593c28588fSJacopo Mondi 	}
28603c28588fSJacopo Mondi 
28613c28588fSJacopo Mondi 	/*
28623c28588fSJacopo Mondi 	 * The MIPI CSI-2 link frequency should comply with the CSI-2
28633c28588fSJacopo Mondi 	 * specification and be lower than 1GHz.
28643c28588fSJacopo Mondi 	 *
28653c28588fSJacopo Mondi 	 * Start from the suggested pixel_rate for the current mode and
28663c28588fSJacopo Mondi 	 * progressively slow it down if it exceeds 1GHz.
28673c28588fSJacopo Mondi 	 */
28683c28588fSJacopo Mondi 	num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes;
2869a89f14bbSJacopo Mondi 	bpp = ov5640_code_to_bpp(sensor, fmt->code);
28703c28588fSJacopo Mondi 	do {
28713c28588fSJacopo Mondi 		pixel_rate = ov5640_pixel_rates[pixel_rate_id];
28723c28588fSJacopo Mondi 		link_freq = pixel_rate * bpp / (2 * num_lanes);
28733c28588fSJacopo Mondi 	} while (link_freq >= 1000000000U &&
28743c28588fSJacopo Mondi 		 ++pixel_rate_id < OV5640_NUM_PIXEL_RATES);
28753c28588fSJacopo Mondi 
28763c28588fSJacopo Mondi 	sensor->current_link_freq = link_freq;
28773c28588fSJacopo Mondi 
28783c28588fSJacopo Mondi 	/*
28793c28588fSJacopo Mondi 	 * Higher link rates require the clock tree to be programmed with
28803c28588fSJacopo Mondi 	 * 'mipi_div' = 1; this has the effect of halving the actual output
28813c28588fSJacopo Mondi 	 * pixel rate in the MIPI domain.
28823c28588fSJacopo Mondi 	 *
28833c28588fSJacopo Mondi 	 * Adjust the pixel rate and link frequency control value to report it
28843c28588fSJacopo Mondi 	 * correctly to userspace.
28853c28588fSJacopo Mondi 	 */
28863c28588fSJacopo Mondi 	if (link_freq > OV5640_LINK_RATE_MAX) {
28873c28588fSJacopo Mondi 		pixel_rate /= 2;
28883c28588fSJacopo Mondi 		link_freq /= 2;
28893c28588fSJacopo Mondi 	}
28903c28588fSJacopo Mondi 
28913c28588fSJacopo Mondi 	for (i = 0; i < ARRAY_SIZE(ov5640_csi2_link_freqs); ++i) {
28923c28588fSJacopo Mondi 		if (ov5640_csi2_link_freqs[i] == link_freq)
28933c28588fSJacopo Mondi 			break;
28943c28588fSJacopo Mondi 	}
28953c28588fSJacopo Mondi 	WARN_ON(i == ARRAY_SIZE(ov5640_csi2_link_freqs));
28963c28588fSJacopo Mondi 
28973c28588fSJacopo Mondi 	__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, pixel_rate);
28983c28588fSJacopo Mondi 	__v4l2_ctrl_s_ctrl(sensor->ctrls.link_freq, i);
28993c28588fSJacopo Mondi 
290032979f67SJacopo Mondi 	timings = ov5640_timings(sensor, mode);
290132979f67SJacopo Mondi 	hblank = timings->htot - mode->width;
290232979f67SJacopo Mondi 	__v4l2_ctrl_modify_range(sensor->ctrls.hblank,
290332979f67SJacopo Mondi 				 hblank, hblank, 1, hblank);
290432979f67SJacopo Mondi 
290519f2e3e6SHugues Fruchet 	vblank = timings->vblank_def;
2906bce93b82SJacopo Mondi 
290719f2e3e6SHugues Fruchet 	if (sensor->current_fr != mode->def_fps) {
290819f2e3e6SHugues Fruchet 		/*
290919f2e3e6SHugues Fruchet 		 * Compute the vertical blanking according to the framerate
291019f2e3e6SHugues Fruchet 		 * configured with s_frame_interval.
291119f2e3e6SHugues Fruchet 		 */
291219f2e3e6SHugues Fruchet 		int fie_num = sensor->frame_interval.numerator;
291319f2e3e6SHugues Fruchet 		int fie_denom = sensor->frame_interval.denominator;
291419f2e3e6SHugues Fruchet 
291519f2e3e6SHugues Fruchet 		vblank = ((fie_num * pixel_rate / fie_denom) / timings->htot) -
291619f2e3e6SHugues Fruchet 			mode->height;
291719f2e3e6SHugues Fruchet 	}
291819f2e3e6SHugues Fruchet 
291919f2e3e6SHugues Fruchet 	__v4l2_ctrl_modify_range(sensor->ctrls.vblank, OV5640_MIN_VBLANK,
292019f2e3e6SHugues Fruchet 				 OV5640_MAX_VTS - mode->height, 1, vblank);
292119f2e3e6SHugues Fruchet 	__v4l2_ctrl_s_ctrl(sensor->ctrls.vblank, vblank);
292219f2e3e6SHugues Fruchet 
292319f2e3e6SHugues Fruchet 	exposure_max = timings->crop.height + vblank - 4;
2924bce93b82SJacopo Mondi 	exposure_val = clamp_t(s32, sensor->ctrls.exposure->val,
2925bce93b82SJacopo Mondi 			       sensor->ctrls.exposure->minimum,
2926bce93b82SJacopo Mondi 			       exposure_max);
292719f2e3e6SHugues Fruchet 
2928bce93b82SJacopo Mondi 	__v4l2_ctrl_modify_range(sensor->ctrls.exposure,
2929bce93b82SJacopo Mondi 				 sensor->ctrls.exposure->minimum,
2930bce93b82SJacopo Mondi 				 exposure_max, 1, exposure_val);
2931bce93b82SJacopo Mondi 
29323c28588fSJacopo Mondi 	return 0;
29333c28588fSJacopo Mondi }
29343c28588fSJacopo Mondi 
293519a81c14SSteve Longerbeam static int ov5640_set_fmt(struct v4l2_subdev *sd,
29360d346d2aSTomi Valkeinen 			  struct v4l2_subdev_state *sd_state,
293719a81c14SSteve Longerbeam 			  struct v4l2_subdev_format *format)
293819a81c14SSteve Longerbeam {
293919a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
294019a81c14SSteve Longerbeam 	const struct ov5640_mode_info *new_mode;
2941e6441fdeSHugues Fruchet 	struct v4l2_mbus_framefmt *mbus_fmt = &format->format;
294219a81c14SSteve Longerbeam 	int ret;
294319a81c14SSteve Longerbeam 
294419a81c14SSteve Longerbeam 	if (format->pad != 0)
294519a81c14SSteve Longerbeam 		return -EINVAL;
294619a81c14SSteve Longerbeam 
294719a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
294819a81c14SSteve Longerbeam 
294919a81c14SSteve Longerbeam 	if (sensor->streaming) {
295019a81c14SSteve Longerbeam 		ret = -EBUSY;
295119a81c14SSteve Longerbeam 		goto out;
295219a81c14SSteve Longerbeam 	}
295319a81c14SSteve Longerbeam 
2954e6441fdeSHugues Fruchet 	ret = ov5640_try_fmt_internal(sd, mbus_fmt,
295519a81c14SSteve Longerbeam 				      sensor->current_fr, &new_mode);
295619a81c14SSteve Longerbeam 	if (ret)
295719a81c14SSteve Longerbeam 		goto out;
295819a81c14SSteve Longerbeam 
2959e738f5ddSMirela Rabulea 	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
2960e738f5ddSMirela Rabulea 		*v4l2_subdev_get_try_format(sd, sd_state, 0) = *mbus_fmt;
2961e738f5ddSMirela Rabulea 		goto out;
2962e738f5ddSMirela Rabulea 	}
296319a81c14SSteve Longerbeam 
29646949d864SHugues Fruchet 	if (new_mode != sensor->current_mode) {
296519f2e3e6SHugues Fruchet 		sensor->current_fr = new_mode->def_fps;
296619a81c14SSteve Longerbeam 		sensor->current_mode = new_mode;
296719a81c14SSteve Longerbeam 		sensor->pending_mode_change = true;
29686949d864SHugues Fruchet 	}
296907115449SJacopo Mondi 	if (mbus_fmt->code != sensor->fmt.code)
2970fb98e29fSHugues Fruchet 		sensor->pending_fmt_change = true;
297107115449SJacopo Mondi 
2972e738f5ddSMirela Rabulea 	/* update format even if code is unchanged, resolution might change */
2973e738f5ddSMirela Rabulea 	sensor->fmt = *mbus_fmt;
2974e738f5ddSMirela Rabulea 
29753c28588fSJacopo Mondi 	ov5640_update_pixel_rate(sensor);
29763c28588fSJacopo Mondi 
297719a81c14SSteve Longerbeam out:
297819a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
297919a81c14SSteve Longerbeam 	return ret;
298019a81c14SSteve Longerbeam }
298119a81c14SSteve Longerbeam 
298266ed85ebSJacopo Mondi static int ov5640_get_selection(struct v4l2_subdev *sd,
298366ed85ebSJacopo Mondi 				struct v4l2_subdev_state *sd_state,
298466ed85ebSJacopo Mondi 				struct v4l2_subdev_selection *sel)
298566ed85ebSJacopo Mondi {
298666ed85ebSJacopo Mondi 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
298766ed85ebSJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
298866ed85ebSJacopo Mondi 	const struct ov5640_timings *timings;
298966ed85ebSJacopo Mondi 
299066ed85ebSJacopo Mondi 	switch (sel->target) {
299166ed85ebSJacopo Mondi 	case V4L2_SEL_TGT_CROP: {
299266ed85ebSJacopo Mondi 		mutex_lock(&sensor->lock);
299366ed85ebSJacopo Mondi 		timings = ov5640_timings(sensor, mode);
299466ed85ebSJacopo Mondi 		sel->r = timings->analog_crop;
299566ed85ebSJacopo Mondi 		mutex_unlock(&sensor->lock);
299666ed85ebSJacopo Mondi 
299766ed85ebSJacopo Mondi 		return 0;
299866ed85ebSJacopo Mondi 	}
299966ed85ebSJacopo Mondi 
300066ed85ebSJacopo Mondi 	case V4L2_SEL_TGT_NATIVE_SIZE:
300166ed85ebSJacopo Mondi 	case V4L2_SEL_TGT_CROP_BOUNDS:
300266ed85ebSJacopo Mondi 		sel->r.top = 0;
300366ed85ebSJacopo Mondi 		sel->r.left = 0;
300466ed85ebSJacopo Mondi 		sel->r.width = OV5640_NATIVE_WIDTH;
300566ed85ebSJacopo Mondi 		sel->r.height = OV5640_NATIVE_HEIGHT;
300666ed85ebSJacopo Mondi 
300766ed85ebSJacopo Mondi 		return 0;
300866ed85ebSJacopo Mondi 
300966ed85ebSJacopo Mondi 	case V4L2_SEL_TGT_CROP_DEFAULT:
301066ed85ebSJacopo Mondi 		sel->r.top = OV5640_PIXEL_ARRAY_TOP;
301166ed85ebSJacopo Mondi 		sel->r.left = OV5640_PIXEL_ARRAY_LEFT;
301266ed85ebSJacopo Mondi 		sel->r.width = OV5640_PIXEL_ARRAY_WIDTH;
301366ed85ebSJacopo Mondi 		sel->r.height = OV5640_PIXEL_ARRAY_HEIGHT;
301466ed85ebSJacopo Mondi 
301566ed85ebSJacopo Mondi 		return 0;
301666ed85ebSJacopo Mondi 	}
301766ed85ebSJacopo Mondi 
301866ed85ebSJacopo Mondi 	return -EINVAL;
301966ed85ebSJacopo Mondi }
302066ed85ebSJacopo Mondi 
3021e3ee691dSHugues Fruchet static int ov5640_set_framefmt(struct ov5640_dev *sensor,
3022e3ee691dSHugues Fruchet 			       struct v4l2_mbus_framefmt *format)
3023e3ee691dSHugues Fruchet {
3024935fbc94SJacopo Mondi 	bool is_jpeg = format->code == MEDIA_BUS_FMT_JPEG_1X8;
3025935fbc94SJacopo Mondi 	const struct ov5640_pixfmt *pixfmt;
3026e3ee691dSHugues Fruchet 	int ret = 0;
3027e3ee691dSHugues Fruchet 
3028935fbc94SJacopo Mondi 	pixfmt = ov5640_code_to_pixfmt(sensor, format->code);
3029e3ee691dSHugues Fruchet 
3030e3ee691dSHugues Fruchet 	/* FORMAT CONTROL00: YUV and RGB formatting */
3031935fbc94SJacopo Mondi 	ret = ov5640_write_reg(sensor, OV5640_REG_FORMAT_CONTROL00,
3032935fbc94SJacopo Mondi 			       pixfmt->ctrl00);
3033e3ee691dSHugues Fruchet 	if (ret)
3034e3ee691dSHugues Fruchet 		return ret;
3035e3ee691dSHugues Fruchet 
3036e3ee691dSHugues Fruchet 	/* FORMAT MUX CONTROL: ISP YUV or RGB */
3037935fbc94SJacopo Mondi 	ret = ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL,
3038935fbc94SJacopo Mondi 			       pixfmt->mux);
3039d47c4126SHugues Fruchet 	if (ret)
3040d47c4126SHugues Fruchet 		return ret;
3041d47c4126SHugues Fruchet 
3042d47c4126SHugues Fruchet 	/*
3043d47c4126SHugues Fruchet 	 * TIMING TC REG21:
3044d47c4126SHugues Fruchet 	 * - [5]:	JPEG enable
3045d47c4126SHugues Fruchet 	 */
3046d47c4126SHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
3047d47c4126SHugues Fruchet 			     BIT(5), is_jpeg ? BIT(5) : 0);
3048d47c4126SHugues Fruchet 	if (ret)
3049d47c4126SHugues Fruchet 		return ret;
3050d47c4126SHugues Fruchet 
3051d47c4126SHugues Fruchet 	/*
3052d47c4126SHugues Fruchet 	 * SYSTEM RESET02:
3053d47c4126SHugues Fruchet 	 * - [4]:	Reset JFIFO
3054d47c4126SHugues Fruchet 	 * - [3]:	Reset SFIFO
3055d47c4126SHugues Fruchet 	 * - [2]:	Reset JPEG
3056d47c4126SHugues Fruchet 	 */
3057d47c4126SHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_RESET02,
3058d47c4126SHugues Fruchet 			     BIT(4) | BIT(3) | BIT(2),
3059d47c4126SHugues Fruchet 			     is_jpeg ? 0 : (BIT(4) | BIT(3) | BIT(2)));
3060d47c4126SHugues Fruchet 	if (ret)
3061d47c4126SHugues Fruchet 		return ret;
3062d47c4126SHugues Fruchet 
3063d47c4126SHugues Fruchet 	/*
3064d47c4126SHugues Fruchet 	 * CLOCK ENABLE02:
3065d47c4126SHugues Fruchet 	 * - [5]:	Enable JPEG 2x clock
3066d47c4126SHugues Fruchet 	 * - [3]:	Enable JPEG clock
3067d47c4126SHugues Fruchet 	 */
3068d47c4126SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_SYS_CLOCK_ENABLE02,
3069d47c4126SHugues Fruchet 			      BIT(5) | BIT(3),
3070d47c4126SHugues Fruchet 			      is_jpeg ? (BIT(5) | BIT(3)) : 0);
3071e3ee691dSHugues Fruchet }
307219a81c14SSteve Longerbeam 
307319a81c14SSteve Longerbeam /*
307419a81c14SSteve Longerbeam  * Sensor Controls.
307519a81c14SSteve Longerbeam  */
307619a81c14SSteve Longerbeam 
307719a81c14SSteve Longerbeam static int ov5640_set_ctrl_hue(struct ov5640_dev *sensor, int value)
307819a81c14SSteve Longerbeam {
307919a81c14SSteve Longerbeam 	int ret;
308019a81c14SSteve Longerbeam 
308119a81c14SSteve Longerbeam 	if (value) {
308219a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
308319a81c14SSteve Longerbeam 				     BIT(0), BIT(0));
308419a81c14SSteve Longerbeam 		if (ret)
308519a81c14SSteve Longerbeam 			return ret;
308619a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_SDE_CTRL1, value);
308719a81c14SSteve Longerbeam 	} else {
308819a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(0), 0);
308919a81c14SSteve Longerbeam 	}
309019a81c14SSteve Longerbeam 
309119a81c14SSteve Longerbeam 	return ret;
309219a81c14SSteve Longerbeam }
309319a81c14SSteve Longerbeam 
309419a81c14SSteve Longerbeam static int ov5640_set_ctrl_contrast(struct ov5640_dev *sensor, int value)
309519a81c14SSteve Longerbeam {
309619a81c14SSteve Longerbeam 	int ret;
309719a81c14SSteve Longerbeam 
309819a81c14SSteve Longerbeam 	if (value) {
309919a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
310019a81c14SSteve Longerbeam 				     BIT(2), BIT(2));
310119a81c14SSteve Longerbeam 		if (ret)
310219a81c14SSteve Longerbeam 			return ret;
310319a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL5,
310419a81c14SSteve Longerbeam 				       value & 0xff);
310519a81c14SSteve Longerbeam 	} else {
310619a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(2), 0);
310719a81c14SSteve Longerbeam 	}
310819a81c14SSteve Longerbeam 
310919a81c14SSteve Longerbeam 	return ret;
311019a81c14SSteve Longerbeam }
311119a81c14SSteve Longerbeam 
311219a81c14SSteve Longerbeam static int ov5640_set_ctrl_saturation(struct ov5640_dev *sensor, int value)
311319a81c14SSteve Longerbeam {
311419a81c14SSteve Longerbeam 	int ret;
311519a81c14SSteve Longerbeam 
311619a81c14SSteve Longerbeam 	if (value) {
311719a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
311819a81c14SSteve Longerbeam 				     BIT(1), BIT(1));
311919a81c14SSteve Longerbeam 		if (ret)
312019a81c14SSteve Longerbeam 			return ret;
312119a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL3,
312219a81c14SSteve Longerbeam 				       value & 0xff);
312319a81c14SSteve Longerbeam 		if (ret)
312419a81c14SSteve Longerbeam 			return ret;
312519a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL4,
312619a81c14SSteve Longerbeam 				       value & 0xff);
312719a81c14SSteve Longerbeam 	} else {
312819a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(1), 0);
312919a81c14SSteve Longerbeam 	}
313019a81c14SSteve Longerbeam 
313119a81c14SSteve Longerbeam 	return ret;
313219a81c14SSteve Longerbeam }
313319a81c14SSteve Longerbeam 
313419a81c14SSteve Longerbeam static int ov5640_set_ctrl_white_balance(struct ov5640_dev *sensor, int awb)
313519a81c14SSteve Longerbeam {
313619a81c14SSteve Longerbeam 	int ret;
313719a81c14SSteve Longerbeam 
313819a81c14SSteve Longerbeam 	ret = ov5640_mod_reg(sensor, OV5640_REG_AWB_MANUAL_CTRL,
313919a81c14SSteve Longerbeam 			     BIT(0), awb ? 0 : 1);
314019a81c14SSteve Longerbeam 	if (ret)
314119a81c14SSteve Longerbeam 		return ret;
314219a81c14SSteve Longerbeam 
314319a81c14SSteve Longerbeam 	if (!awb) {
314419a81c14SSteve Longerbeam 		u16 red = (u16)sensor->ctrls.red_balance->val;
314519a81c14SSteve Longerbeam 		u16 blue = (u16)sensor->ctrls.blue_balance->val;
314619a81c14SSteve Longerbeam 
314719a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_R_GAIN, red);
314819a81c14SSteve Longerbeam 		if (ret)
314919a81c14SSteve Longerbeam 			return ret;
315019a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_B_GAIN, blue);
315119a81c14SSteve Longerbeam 	}
315219a81c14SSteve Longerbeam 
315319a81c14SSteve Longerbeam 	return ret;
315419a81c14SSteve Longerbeam }
315519a81c14SSteve Longerbeam 
31563cca8ef5SHugues Fruchet static int ov5640_set_ctrl_exposure(struct ov5640_dev *sensor,
31573cca8ef5SHugues Fruchet 				    enum v4l2_exposure_auto_type auto_exposure)
315819a81c14SSteve Longerbeam {
315919a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
31603cca8ef5SHugues Fruchet 	bool auto_exp = (auto_exposure == V4L2_EXPOSURE_AUTO);
316119a81c14SSteve Longerbeam 	int ret = 0;
316219a81c14SSteve Longerbeam 
316319a81c14SSteve Longerbeam 	if (ctrls->auto_exp->is_new) {
31643cca8ef5SHugues Fruchet 		ret = ov5640_set_autoexposure(sensor, auto_exp);
316519a81c14SSteve Longerbeam 		if (ret)
316619a81c14SSteve Longerbeam 			return ret;
316719a81c14SSteve Longerbeam 	}
316819a81c14SSteve Longerbeam 
31693cca8ef5SHugues Fruchet 	if (!auto_exp && ctrls->exposure->is_new) {
317019a81c14SSteve Longerbeam 		u16 max_exp;
317119a81c14SSteve Longerbeam 
317219a81c14SSteve Longerbeam 		ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_VTS,
317319a81c14SSteve Longerbeam 					&max_exp);
317419a81c14SSteve Longerbeam 		if (ret)
317519a81c14SSteve Longerbeam 			return ret;
317619a81c14SSteve Longerbeam 		ret = ov5640_get_vts(sensor);
317719a81c14SSteve Longerbeam 		if (ret < 0)
317819a81c14SSteve Longerbeam 			return ret;
317919a81c14SSteve Longerbeam 		max_exp += ret;
31806146fde3SHugues Fruchet 		ret = 0;
318119a81c14SSteve Longerbeam 
318219a81c14SSteve Longerbeam 		if (ctrls->exposure->val < max_exp)
318319a81c14SSteve Longerbeam 			ret = ov5640_set_exposure(sensor, ctrls->exposure->val);
318419a81c14SSteve Longerbeam 	}
318519a81c14SSteve Longerbeam 
318619a81c14SSteve Longerbeam 	return ret;
318719a81c14SSteve Longerbeam }
318819a81c14SSteve Longerbeam 
31893cca8ef5SHugues Fruchet static int ov5640_set_ctrl_gain(struct ov5640_dev *sensor, bool auto_gain)
319019a81c14SSteve Longerbeam {
319119a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
319219a81c14SSteve Longerbeam 	int ret = 0;
319319a81c14SSteve Longerbeam 
319419a81c14SSteve Longerbeam 	if (ctrls->auto_gain->is_new) {
31953cca8ef5SHugues Fruchet 		ret = ov5640_set_autogain(sensor, auto_gain);
319619a81c14SSteve Longerbeam 		if (ret)
319719a81c14SSteve Longerbeam 			return ret;
319819a81c14SSteve Longerbeam 	}
319919a81c14SSteve Longerbeam 
32003cca8ef5SHugues Fruchet 	if (!auto_gain && ctrls->gain->is_new)
32013cca8ef5SHugues Fruchet 		ret = ov5640_set_gain(sensor, ctrls->gain->val);
320219a81c14SSteve Longerbeam 
320319a81c14SSteve Longerbeam 	return ret;
320419a81c14SSteve Longerbeam }
320519a81c14SSteve Longerbeam 
32069f6d7bacSChen-Yu Tsai static const char * const test_pattern_menu[] = {
32079f6d7bacSChen-Yu Tsai 	"Disabled",
32089f6d7bacSChen-Yu Tsai 	"Color bars",
3209bddc5cdfSChen-Yu Tsai 	"Color bars w/ rolling bar",
3210bddc5cdfSChen-Yu Tsai 	"Color squares",
3211bddc5cdfSChen-Yu Tsai 	"Color squares w/ rolling bar",
32129f6d7bacSChen-Yu Tsai };
32139f6d7bacSChen-Yu Tsai 
3214a0c29afbSChen-Yu Tsai #define OV5640_TEST_ENABLE		BIT(7)
3215a0c29afbSChen-Yu Tsai #define OV5640_TEST_ROLLING		BIT(6)	/* rolling horizontal bar */
3216a0c29afbSChen-Yu Tsai #define OV5640_TEST_TRANSPARENT		BIT(5)
3217a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE_BW		BIT(4)	/* black & white squares */
3218a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_STANDARD	(0 << 2)
3219a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_1	(1 << 2)
3220a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_HOR_CHANGE	(2 << 2)
3221a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_2	(3 << 2)
3222a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR			(0 << 0)
3223a0c29afbSChen-Yu Tsai #define OV5640_TEST_RANDOM		(1 << 0)
3224a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE		(2 << 0)
3225a0c29afbSChen-Yu Tsai #define OV5640_TEST_BLACK		(3 << 0)
3226a0c29afbSChen-Yu Tsai 
3227a0c29afbSChen-Yu Tsai static const u8 test_pattern_val[] = {
3228a0c29afbSChen-Yu Tsai 	0,
32292aff1fc3SChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_BAR_VERT_CHANGE_1 |
3230a0c29afbSChen-Yu Tsai 		OV5640_TEST_BAR,
3231bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_ROLLING |
3232bddc5cdfSChen-Yu Tsai 		OV5640_TEST_BAR_VERT_CHANGE_1 | OV5640_TEST_BAR,
3233bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_SQUARE,
3234bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_ROLLING | OV5640_TEST_SQUARE,
3235a0c29afbSChen-Yu Tsai };
3236a0c29afbSChen-Yu Tsai 
323719a81c14SSteve Longerbeam static int ov5640_set_ctrl_test_pattern(struct ov5640_dev *sensor, int value)
323819a81c14SSteve Longerbeam {
3239a0c29afbSChen-Yu Tsai 	return ov5640_write_reg(sensor, OV5640_REG_PRE_ISP_TEST_SET1,
3240a0c29afbSChen-Yu Tsai 				test_pattern_val[value]);
324119a81c14SSteve Longerbeam }
324219a81c14SSteve Longerbeam 
32431068fecaSMylène Josserand static int ov5640_set_ctrl_light_freq(struct ov5640_dev *sensor, int value)
32441068fecaSMylène Josserand {
32451068fecaSMylène Josserand 	int ret;
32461068fecaSMylène Josserand 
32471068fecaSMylène Josserand 	ret = ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL01, BIT(7),
32481068fecaSMylène Josserand 			     (value == V4L2_CID_POWER_LINE_FREQUENCY_AUTO) ?
32491068fecaSMylène Josserand 			     0 : BIT(7));
32501068fecaSMylène Josserand 	if (ret)
32511068fecaSMylène Josserand 		return ret;
32521068fecaSMylène Josserand 
32531068fecaSMylène Josserand 	return ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL00, BIT(2),
32541068fecaSMylène Josserand 			      (value == V4L2_CID_POWER_LINE_FREQUENCY_50HZ) ?
32551068fecaSMylène Josserand 			      BIT(2) : 0);
32561068fecaSMylène Josserand }
32571068fecaSMylène Josserand 
3258ce85705aSHugues Fruchet static int ov5640_set_ctrl_hflip(struct ov5640_dev *sensor, int value)
3259ce85705aSHugues Fruchet {
3260ce85705aSHugues Fruchet 	/*
3261c3f3ba3eSHugues Fruchet 	 * If sensor is mounted upside down, mirror logic is inversed.
3262c3f3ba3eSHugues Fruchet 	 *
3263ce85705aSHugues Fruchet 	 * Sensor is a BSI (Back Side Illuminated) one,
3264ce85705aSHugues Fruchet 	 * so image captured is physically mirrored.
3265ce85705aSHugues Fruchet 	 * This is why mirror logic is inversed in
3266ce85705aSHugues Fruchet 	 * order to cancel this mirror effect.
3267ce85705aSHugues Fruchet 	 */
3268ce85705aSHugues Fruchet 
3269ce85705aSHugues Fruchet 	/*
3270ce85705aSHugues Fruchet 	 * TIMING TC REG21:
3271ce85705aSHugues Fruchet 	 * - [2]:	ISP mirror
3272ce85705aSHugues Fruchet 	 * - [1]:	Sensor mirror
3273ce85705aSHugues Fruchet 	 */
3274ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
3275ce85705aSHugues Fruchet 			      BIT(2) | BIT(1),
3276c3f3ba3eSHugues Fruchet 			      (!(value ^ sensor->upside_down)) ?
3277c3f3ba3eSHugues Fruchet 			      (BIT(2) | BIT(1)) : 0);
3278ce85705aSHugues Fruchet }
3279ce85705aSHugues Fruchet 
3280ce85705aSHugues Fruchet static int ov5640_set_ctrl_vflip(struct ov5640_dev *sensor, int value)
3281ce85705aSHugues Fruchet {
3282c3f3ba3eSHugues Fruchet 	/* If sensor is mounted upside down, flip logic is inversed */
3283c3f3ba3eSHugues Fruchet 
3284ce85705aSHugues Fruchet 	/*
3285ce85705aSHugues Fruchet 	 * TIMING TC REG20:
3286ce85705aSHugues Fruchet 	 * - [2]:	ISP vflip
3287ce85705aSHugues Fruchet 	 * - [1]:	Sensor vflip
3288ce85705aSHugues Fruchet 	 */
3289ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20,
3290ce85705aSHugues Fruchet 			      BIT(2) | BIT(1),
3291c3f3ba3eSHugues Fruchet 			      (value ^ sensor->upside_down) ?
3292c3f3ba3eSHugues Fruchet 			      (BIT(2) | BIT(1)) : 0);
3293ce85705aSHugues Fruchet }
3294ce85705aSHugues Fruchet 
3295bce93b82SJacopo Mondi static int ov5640_set_ctrl_vblank(struct ov5640_dev *sensor, int value)
3296bce93b82SJacopo Mondi {
3297bce93b82SJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
3298bce93b82SJacopo Mondi 
3299bce93b82SJacopo Mondi 	/* Update the VTOT timing register value. */
3300bce93b82SJacopo Mondi 	return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS,
3301bce93b82SJacopo Mondi 				  mode->height + value);
3302bce93b82SJacopo Mondi }
3303bce93b82SJacopo Mondi 
330419a81c14SSteve Longerbeam static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
330519a81c14SSteve Longerbeam {
330619a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
330719a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
330819a81c14SSteve Longerbeam 	int val;
330919a81c14SSteve Longerbeam 
331019a81c14SSteve Longerbeam 	/* v4l2_ctrl_lock() locks our own mutex */
331119a81c14SSteve Longerbeam 
331285644a9bSPaul Elder 	if (!pm_runtime_get_if_in_use(&sensor->i2c_client->dev))
331385644a9bSPaul Elder 		return 0;
331485644a9bSPaul Elder 
331519a81c14SSteve Longerbeam 	switch (ctrl->id) {
331619a81c14SSteve Longerbeam 	case V4L2_CID_AUTOGAIN:
331719a81c14SSteve Longerbeam 		val = ov5640_get_gain(sensor);
331819a81c14SSteve Longerbeam 		if (val < 0)
331919a81c14SSteve Longerbeam 			return val;
332019a81c14SSteve Longerbeam 		sensor->ctrls.gain->val = val;
332119a81c14SSteve Longerbeam 		break;
332219a81c14SSteve Longerbeam 	case V4L2_CID_EXPOSURE_AUTO:
332319a81c14SSteve Longerbeam 		val = ov5640_get_exposure(sensor);
332419a81c14SSteve Longerbeam 		if (val < 0)
332519a81c14SSteve Longerbeam 			return val;
332619a81c14SSteve Longerbeam 		sensor->ctrls.exposure->val = val;
332719a81c14SSteve Longerbeam 		break;
332819a81c14SSteve Longerbeam 	}
332919a81c14SSteve Longerbeam 
3330*e13064a3SAndrey Skvortsov 	pm_runtime_mark_last_busy(&sensor->i2c_client->dev);
333185644a9bSPaul Elder 	pm_runtime_put_autosuspend(&sensor->i2c_client->dev);
333285644a9bSPaul Elder 
333319a81c14SSteve Longerbeam 	return 0;
333419a81c14SSteve Longerbeam }
333519a81c14SSteve Longerbeam 
333619a81c14SSteve Longerbeam static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl)
333719a81c14SSteve Longerbeam {
333819a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
333919a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
3340bce93b82SJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
3341bce93b82SJacopo Mondi 	const struct ov5640_timings *timings;
3342bce93b82SJacopo Mondi 	unsigned int exp_max;
334319a81c14SSteve Longerbeam 	int ret;
334419a81c14SSteve Longerbeam 
334519a81c14SSteve Longerbeam 	/* v4l2_ctrl_lock() locks our own mutex */
334619a81c14SSteve Longerbeam 
3347bce93b82SJacopo Mondi 	switch (ctrl->id) {
3348bce93b82SJacopo Mondi 	case V4L2_CID_VBLANK:
3349bce93b82SJacopo Mondi 		/* Update the exposure range to the newly programmed vblank. */
3350bce93b82SJacopo Mondi 		timings = ov5640_timings(sensor, mode);
3351bce93b82SJacopo Mondi 		exp_max = mode->height + ctrl->val - 4;
3352bce93b82SJacopo Mondi 		__v4l2_ctrl_modify_range(sensor->ctrls.exposure,
3353bce93b82SJacopo Mondi 					 sensor->ctrls.exposure->minimum,
3354bce93b82SJacopo Mondi 					 exp_max, sensor->ctrls.exposure->step,
3355bce93b82SJacopo Mondi 					 timings->vblank_def);
3356bce93b82SJacopo Mondi 		break;
3357bce93b82SJacopo Mondi 	}
3358bce93b82SJacopo Mondi 
335919a81c14SSteve Longerbeam 	/*
336019a81c14SSteve Longerbeam 	 * If the device is not powered up by the host driver do
336119a81c14SSteve Longerbeam 	 * not apply any controls to H/W at this time. Instead
336285644a9bSPaul Elder 	 * the controls will be restored at start streaming time.
336319a81c14SSteve Longerbeam 	 */
336485644a9bSPaul Elder 	if (!pm_runtime_get_if_in_use(&sensor->i2c_client->dev))
336519a81c14SSteve Longerbeam 		return 0;
336619a81c14SSteve Longerbeam 
336719a81c14SSteve Longerbeam 	switch (ctrl->id) {
336819a81c14SSteve Longerbeam 	case V4L2_CID_AUTOGAIN:
336919a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_gain(sensor, ctrl->val);
337019a81c14SSteve Longerbeam 		break;
337119a81c14SSteve Longerbeam 	case V4L2_CID_EXPOSURE_AUTO:
337219a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_exposure(sensor, ctrl->val);
337319a81c14SSteve Longerbeam 		break;
337419a81c14SSteve Longerbeam 	case V4L2_CID_AUTO_WHITE_BALANCE:
337519a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_white_balance(sensor, ctrl->val);
337619a81c14SSteve Longerbeam 		break;
337719a81c14SSteve Longerbeam 	case V4L2_CID_HUE:
337819a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_hue(sensor, ctrl->val);
337919a81c14SSteve Longerbeam 		break;
338019a81c14SSteve Longerbeam 	case V4L2_CID_CONTRAST:
338119a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_contrast(sensor, ctrl->val);
338219a81c14SSteve Longerbeam 		break;
338319a81c14SSteve Longerbeam 	case V4L2_CID_SATURATION:
338419a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_saturation(sensor, ctrl->val);
338519a81c14SSteve Longerbeam 		break;
338619a81c14SSteve Longerbeam 	case V4L2_CID_TEST_PATTERN:
338719a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_test_pattern(sensor, ctrl->val);
338819a81c14SSteve Longerbeam 		break;
33891068fecaSMylène Josserand 	case V4L2_CID_POWER_LINE_FREQUENCY:
33901068fecaSMylène Josserand 		ret = ov5640_set_ctrl_light_freq(sensor, ctrl->val);
33911068fecaSMylène Josserand 		break;
3392ce85705aSHugues Fruchet 	case V4L2_CID_HFLIP:
3393ce85705aSHugues Fruchet 		ret = ov5640_set_ctrl_hflip(sensor, ctrl->val);
3394ce85705aSHugues Fruchet 		break;
3395ce85705aSHugues Fruchet 	case V4L2_CID_VFLIP:
3396ce85705aSHugues Fruchet 		ret = ov5640_set_ctrl_vflip(sensor, ctrl->val);
3397ce85705aSHugues Fruchet 		break;
3398bce93b82SJacopo Mondi 	case V4L2_CID_VBLANK:
3399bce93b82SJacopo Mondi 		ret = ov5640_set_ctrl_vblank(sensor, ctrl->val);
3400bce93b82SJacopo Mondi 		break;
340119a81c14SSteve Longerbeam 	default:
340219a81c14SSteve Longerbeam 		ret = -EINVAL;
340319a81c14SSteve Longerbeam 		break;
340419a81c14SSteve Longerbeam 	}
340519a81c14SSteve Longerbeam 
3406*e13064a3SAndrey Skvortsov 	pm_runtime_mark_last_busy(&sensor->i2c_client->dev);
340785644a9bSPaul Elder 	pm_runtime_put_autosuspend(&sensor->i2c_client->dev);
340885644a9bSPaul Elder 
340919a81c14SSteve Longerbeam 	return ret;
341019a81c14SSteve Longerbeam }
341119a81c14SSteve Longerbeam 
341219a81c14SSteve Longerbeam static const struct v4l2_ctrl_ops ov5640_ctrl_ops = {
341319a81c14SSteve Longerbeam 	.g_volatile_ctrl = ov5640_g_volatile_ctrl,
341419a81c14SSteve Longerbeam 	.s_ctrl = ov5640_s_ctrl,
341519a81c14SSteve Longerbeam };
341619a81c14SSteve Longerbeam 
341719a81c14SSteve Longerbeam static int ov5640_init_controls(struct ov5640_dev *sensor)
341819a81c14SSteve Longerbeam {
341922845bf2SJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
342019a81c14SSteve Longerbeam 	const struct v4l2_ctrl_ops *ops = &ov5640_ctrl_ops;
342119a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
342219a81c14SSteve Longerbeam 	struct v4l2_ctrl_handler *hdl = &ctrls->handler;
34231066fc1cSJacopo Mondi 	struct v4l2_fwnode_device_properties props;
342432979f67SJacopo Mondi 	const struct ov5640_timings *timings;
3425bce93b82SJacopo Mondi 	unsigned int max_vblank;
342632979f67SJacopo Mondi 	unsigned int hblank;
342719a81c14SSteve Longerbeam 	int ret;
342819a81c14SSteve Longerbeam 
342919a81c14SSteve Longerbeam 	v4l2_ctrl_handler_init(hdl, 32);
343019a81c14SSteve Longerbeam 
343119a81c14SSteve Longerbeam 	/* we can use our own mutex for the ctrl lock */
343219a81c14SSteve Longerbeam 	hdl->lock = &sensor->lock;
343319a81c14SSteve Longerbeam 
3434cc196e48SBenoit Parrot 	/* Clock related controls */
3435cc196e48SBenoit Parrot 	ctrls->pixel_rate = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE,
343622845bf2SJacopo Mondi 			      ov5640_pixel_rates[OV5640_NUM_PIXEL_RATES - 1],
343722845bf2SJacopo Mondi 			      ov5640_pixel_rates[0], 1,
343822845bf2SJacopo Mondi 			      ov5640_pixel_rates[mode->pixel_rate]);
3439cc196e48SBenoit Parrot 
34407a3b8d4bSJacopo Mondi 	ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops,
34417a3b8d4bSJacopo Mondi 					V4L2_CID_LINK_FREQ,
34427a3b8d4bSJacopo Mondi 					ARRAY_SIZE(ov5640_csi2_link_freqs) - 1,
34437a3b8d4bSJacopo Mondi 					OV5640_DEFAULT_LINK_FREQ,
34447a3b8d4bSJacopo Mondi 					ov5640_csi2_link_freqs);
34457a3b8d4bSJacopo Mondi 
344632979f67SJacopo Mondi 	timings = ov5640_timings(sensor, mode);
344732979f67SJacopo Mondi 	hblank = timings->htot - mode->width;
344832979f67SJacopo Mondi 	ctrls->hblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HBLANK, hblank,
344932979f67SJacopo Mondi 					  hblank, 1, hblank);
345032979f67SJacopo Mondi 
3451bce93b82SJacopo Mondi 	max_vblank = OV5640_MAX_VTS - mode->height;
3452bce93b82SJacopo Mondi 	ctrls->vblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VBLANK,
3453bce93b82SJacopo Mondi 					  OV5640_MIN_VBLANK, max_vblank,
3454bce93b82SJacopo Mondi 					  1, timings->vblank_def);
3455bce93b82SJacopo Mondi 
345619a81c14SSteve Longerbeam 	/* Auto/manual white balance */
345719a81c14SSteve Longerbeam 	ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops,
345819a81c14SSteve Longerbeam 					   V4L2_CID_AUTO_WHITE_BALANCE,
345919a81c14SSteve Longerbeam 					   0, 1, 1, 1);
346019a81c14SSteve Longerbeam 	ctrls->blue_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BLUE_BALANCE,
346119a81c14SSteve Longerbeam 						0, 4095, 1, 0);
346219a81c14SSteve Longerbeam 	ctrls->red_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_RED_BALANCE,
346319a81c14SSteve Longerbeam 					       0, 4095, 1, 0);
346419a81c14SSteve Longerbeam 	/* Auto/manual exposure */
346519a81c14SSteve Longerbeam 	ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops,
346619a81c14SSteve Longerbeam 						 V4L2_CID_EXPOSURE_AUTO,
346719a81c14SSteve Longerbeam 						 V4L2_EXPOSURE_MANUAL, 0,
346819a81c14SSteve Longerbeam 						 V4L2_EXPOSURE_AUTO);
346919a81c14SSteve Longerbeam 	ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
347019a81c14SSteve Longerbeam 					    0, 65535, 1, 0);
347119a81c14SSteve Longerbeam 	/* Auto/manual gain */
347219a81c14SSteve Longerbeam 	ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN,
347319a81c14SSteve Longerbeam 					     0, 1, 1, 1);
347419a81c14SSteve Longerbeam 	ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN,
347519a81c14SSteve Longerbeam 					0, 1023, 1, 0);
347619a81c14SSteve Longerbeam 
347719a81c14SSteve Longerbeam 	ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION,
347819a81c14SSteve Longerbeam 					      0, 255, 1, 64);
347919a81c14SSteve Longerbeam 	ctrls->hue = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HUE,
348019a81c14SSteve Longerbeam 				       0, 359, 1, 0);
348119a81c14SSteve Longerbeam 	ctrls->contrast = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST,
348219a81c14SSteve Longerbeam 					    0, 255, 1, 0);
348319a81c14SSteve Longerbeam 	ctrls->test_pattern =
348419a81c14SSteve Longerbeam 		v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN,
348519a81c14SSteve Longerbeam 					     ARRAY_SIZE(test_pattern_menu) - 1,
348619a81c14SSteve Longerbeam 					     0, 0, test_pattern_menu);
3487ce85705aSHugues Fruchet 	ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP,
3488ce85705aSHugues Fruchet 					 0, 1, 1, 0);
3489ce85705aSHugues Fruchet 	ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP,
3490ce85705aSHugues Fruchet 					 0, 1, 1, 0);
349119a81c14SSteve Longerbeam 
34921068fecaSMylène Josserand 	ctrls->light_freq =
34931068fecaSMylène Josserand 		v4l2_ctrl_new_std_menu(hdl, ops,
34941068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY,
34951068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
34961068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
34971068fecaSMylène Josserand 
349819a81c14SSteve Longerbeam 	if (hdl->error) {
349919a81c14SSteve Longerbeam 		ret = hdl->error;
350019a81c14SSteve Longerbeam 		goto free_ctrls;
350119a81c14SSteve Longerbeam 	}
350219a81c14SSteve Longerbeam 
35031066fc1cSJacopo Mondi 	ret = v4l2_fwnode_device_parse(&sensor->i2c_client->dev, &props);
35041066fc1cSJacopo Mondi 	if (ret)
35051066fc1cSJacopo Mondi 		goto free_ctrls;
35061066fc1cSJacopo Mondi 
35071066fc1cSJacopo Mondi 	if (props.rotation == 180)
35081066fc1cSJacopo Mondi 		sensor->upside_down = true;
35091066fc1cSJacopo Mondi 
35101066fc1cSJacopo Mondi 	ret = v4l2_ctrl_new_fwnode_properties(hdl, ops, &props);
35111066fc1cSJacopo Mondi 	if (ret)
35121066fc1cSJacopo Mondi 		goto free_ctrls;
35131066fc1cSJacopo Mondi 
3514cc196e48SBenoit Parrot 	ctrls->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY;
35157a3b8d4bSJacopo Mondi 	ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
351632979f67SJacopo Mondi 	ctrls->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
351719a81c14SSteve Longerbeam 	ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE;
351819a81c14SSteve Longerbeam 	ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE;
351919a81c14SSteve Longerbeam 
352019a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false);
352119a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(2, &ctrls->auto_gain, 0, true);
352219a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(2, &ctrls->auto_exp, 1, true);
352319a81c14SSteve Longerbeam 
352419a81c14SSteve Longerbeam 	sensor->sd.ctrl_handler = hdl;
352519a81c14SSteve Longerbeam 	return 0;
352619a81c14SSteve Longerbeam 
352719a81c14SSteve Longerbeam free_ctrls:
352819a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(hdl);
352919a81c14SSteve Longerbeam 	return ret;
353019a81c14SSteve Longerbeam }
353119a81c14SSteve Longerbeam 
353219a81c14SSteve Longerbeam static int ov5640_enum_frame_size(struct v4l2_subdev *sd,
35330d346d2aSTomi Valkeinen 				  struct v4l2_subdev_state *sd_state,
353419a81c14SSteve Longerbeam 				  struct v4l2_subdev_frame_size_enum *fse)
353519a81c14SSteve Longerbeam {
3536a89f14bbSJacopo Mondi 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
3537a89f14bbSJacopo Mondi 	u32 bpp = ov5640_code_to_bpp(sensor, fse->code);
35387dcb3a2fSJacopo Mondi 	unsigned int index = fse->index;
35397dcb3a2fSJacopo Mondi 
354019a81c14SSteve Longerbeam 	if (fse->pad != 0)
354119a81c14SSteve Longerbeam 		return -EINVAL;
35427dcb3a2fSJacopo Mondi 	if (!bpp)
354319a81c14SSteve Longerbeam 		return -EINVAL;
354419a81c14SSteve Longerbeam 
35457dcb3a2fSJacopo Mondi 	/* Only low-resolution modes are supported for 24bpp formats. */
35467dcb3a2fSJacopo Mondi 	if (bpp == 24 && index >= OV5640_MODE_720P_1280_720)
35477dcb3a2fSJacopo Mondi 		return -EINVAL;
35487dcb3a2fSJacopo Mondi 
35497dcb3a2fSJacopo Mondi 	/* FIXME: Low resolution modes don't work in 8bpp formats. */
35507dcb3a2fSJacopo Mondi 	if (bpp == 8)
35517dcb3a2fSJacopo Mondi 		index += OV5640_MODE_720P_1280_720;
35527dcb3a2fSJacopo Mondi 
35537dcb3a2fSJacopo Mondi 	if (index >= OV5640_NUM_MODES)
35547dcb3a2fSJacopo Mondi 		return -EINVAL;
35557dcb3a2fSJacopo Mondi 
35567dcb3a2fSJacopo Mondi 	fse->min_width = ov5640_mode_data[index].width;
355741d8d7f5SHugues Fruchet 	fse->max_width = fse->min_width;
35587dcb3a2fSJacopo Mondi 	fse->min_height = ov5640_mode_data[index].height;
355941d8d7f5SHugues Fruchet 	fse->max_height = fse->min_height;
356019a81c14SSteve Longerbeam 
356119a81c14SSteve Longerbeam 	return 0;
356219a81c14SSteve Longerbeam }
356319a81c14SSteve Longerbeam 
356419a81c14SSteve Longerbeam static int ov5640_enum_frame_interval(
356519a81c14SSteve Longerbeam 	struct v4l2_subdev *sd,
35660d346d2aSTomi Valkeinen 	struct v4l2_subdev_state *sd_state,
356719a81c14SSteve Longerbeam 	struct v4l2_subdev_frame_interval_enum *fie)
356819a81c14SSteve Longerbeam {
356919a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
3570f33b56d3SGuoniu.zhou 	const struct ov5640_mode_info *mode;
357119a81c14SSteve Longerbeam 	struct v4l2_fract tpf;
357219a81c14SSteve Longerbeam 	int ret;
357319a81c14SSteve Longerbeam 
357419a81c14SSteve Longerbeam 	if (fie->pad != 0)
357519a81c14SSteve Longerbeam 		return -EINVAL;
357619a81c14SSteve Longerbeam 	if (fie->index >= OV5640_NUM_FRAMERATES)
357719a81c14SSteve Longerbeam 		return -EINVAL;
357819a81c14SSteve Longerbeam 
3579f33b56d3SGuoniu.zhou 	mode = ov5640_find_mode(sensor, fie->width, fie->height, false);
3580f33b56d3SGuoniu.zhou 	if (!mode)
3581f33b56d3SGuoniu.zhou 		return -EINVAL;
3582f33b56d3SGuoniu.zhou 
358319a81c14SSteve Longerbeam 	tpf.numerator = 1;
358419a81c14SSteve Longerbeam 	tpf.denominator = ov5640_framerates[fie->index];
358519a81c14SSteve Longerbeam 
3586f33b56d3SGuoniu.zhou 	ret = ov5640_try_frame_interval(sensor, &tpf, mode);
358719a81c14SSteve Longerbeam 	if (ret < 0)
358819a81c14SSteve Longerbeam 		return -EINVAL;
358919a81c14SSteve Longerbeam 
359019a81c14SSteve Longerbeam 	fie->interval = tpf;
359119a81c14SSteve Longerbeam 	return 0;
359219a81c14SSteve Longerbeam }
359319a81c14SSteve Longerbeam 
359419a81c14SSteve Longerbeam static int ov5640_g_frame_interval(struct v4l2_subdev *sd,
359519a81c14SSteve Longerbeam 				   struct v4l2_subdev_frame_interval *fi)
359619a81c14SSteve Longerbeam {
359719a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
359819a81c14SSteve Longerbeam 
359919a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
360019a81c14SSteve Longerbeam 	fi->interval = sensor->frame_interval;
360119a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
360219a81c14SSteve Longerbeam 
360319a81c14SSteve Longerbeam 	return 0;
360419a81c14SSteve Longerbeam }
360519a81c14SSteve Longerbeam 
360619a81c14SSteve Longerbeam static int ov5640_s_frame_interval(struct v4l2_subdev *sd,
360719a81c14SSteve Longerbeam 				   struct v4l2_subdev_frame_interval *fi)
360819a81c14SSteve Longerbeam {
360919a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
361019a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
361119a81c14SSteve Longerbeam 	int frame_rate, ret = 0;
361219a81c14SSteve Longerbeam 
361319a81c14SSteve Longerbeam 	if (fi->pad != 0)
361419a81c14SSteve Longerbeam 		return -EINVAL;
361519a81c14SSteve Longerbeam 
361619a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
361719a81c14SSteve Longerbeam 
361819a81c14SSteve Longerbeam 	if (sensor->streaming) {
361919a81c14SSteve Longerbeam 		ret = -EBUSY;
362019a81c14SSteve Longerbeam 		goto out;
362119a81c14SSteve Longerbeam 	}
362219a81c14SSteve Longerbeam 
362319a81c14SSteve Longerbeam 	mode = sensor->current_mode;
362419a81c14SSteve Longerbeam 
3625f33b56d3SGuoniu.zhou 	frame_rate = ov5640_try_frame_interval(sensor, &fi->interval, mode);
3626e823fb16SMaxime Ripard 	if (frame_rate < 0) {
3627e823fb16SMaxime Ripard 		/* Always return a valid frame interval value */
3628e823fb16SMaxime Ripard 		fi->interval = sensor->frame_interval;
3629e823fb16SMaxime Ripard 		goto out;
3630e823fb16SMaxime Ripard 	}
363119a81c14SSteve Longerbeam 
3632b6ae5022SJacopo Mondi 	mode = ov5640_find_mode(sensor, mode->width, mode->height, true);
36333c4a7372SHugues Fruchet 	if (!mode) {
36343c4a7372SHugues Fruchet 		ret = -EINVAL;
36353c4a7372SHugues Fruchet 		goto out;
36363c4a7372SHugues Fruchet 	}
36373c4a7372SHugues Fruchet 
3638b6ae5022SJacopo Mondi 	if (ov5640_framerates[frame_rate] > ov5640_framerates[mode->max_fps]) {
3639b6ae5022SJacopo Mondi 		ret = -EINVAL;
3640b6ae5022SJacopo Mondi 		goto out;
3641b6ae5022SJacopo Mondi 	}
3642b6ae5022SJacopo Mondi 
36430929983eSHugues Fruchet 	if (mode != sensor->current_mode ||
36440929983eSHugues Fruchet 	    frame_rate != sensor->current_fr) {
36450929983eSHugues Fruchet 		sensor->current_fr = frame_rate;
36460929983eSHugues Fruchet 		sensor->frame_interval = fi->interval;
36473c4a7372SHugues Fruchet 		sensor->current_mode = mode;
364819a81c14SSteve Longerbeam 		sensor->pending_mode_change = true;
3649cc196e48SBenoit Parrot 
365019f2e3e6SHugues Fruchet 		ov5640_update_pixel_rate(sensor);
36516949d864SHugues Fruchet 	}
365219a81c14SSteve Longerbeam out:
365319a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
365419a81c14SSteve Longerbeam 	return ret;
365519a81c14SSteve Longerbeam }
365619a81c14SSteve Longerbeam 
365719a81c14SSteve Longerbeam static int ov5640_enum_mbus_code(struct v4l2_subdev *sd,
36580d346d2aSTomi Valkeinen 				 struct v4l2_subdev_state *sd_state,
365919a81c14SSteve Longerbeam 				 struct v4l2_subdev_mbus_code_enum *code)
366019a81c14SSteve Longerbeam {
3661a89f14bbSJacopo Mondi 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
3662a89f14bbSJacopo Mondi 	const struct ov5640_pixfmt *formats;
3663a89f14bbSJacopo Mondi 	unsigned int num_formats;
3664a89f14bbSJacopo Mondi 
3665a89f14bbSJacopo Mondi 	if (ov5640_is_csi2(sensor)) {
3666a89f14bbSJacopo Mondi 		formats = ov5640_csi2_formats;
3667a89f14bbSJacopo Mondi 		num_formats = ARRAY_SIZE(ov5640_csi2_formats) - 1;
3668a89f14bbSJacopo Mondi 	} else {
3669a89f14bbSJacopo Mondi 		formats = ov5640_dvp_formats;
3670a89f14bbSJacopo Mondi 		num_formats = ARRAY_SIZE(ov5640_dvp_formats) - 1;
3671a89f14bbSJacopo Mondi 	}
3672a89f14bbSJacopo Mondi 
3673a89f14bbSJacopo Mondi 	if (code->index >= num_formats)
367419a81c14SSteve Longerbeam 		return -EINVAL;
367519a81c14SSteve Longerbeam 
3676a89f14bbSJacopo Mondi 	code->code = formats[code->index].code;
3677a89f14bbSJacopo Mondi 
367819a81c14SSteve Longerbeam 	return 0;
367919a81c14SSteve Longerbeam }
368019a81c14SSteve Longerbeam 
368119a81c14SSteve Longerbeam static int ov5640_s_stream(struct v4l2_subdev *sd, int enable)
368219a81c14SSteve Longerbeam {
368319a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
368419a81c14SSteve Longerbeam 	int ret = 0;
368519a81c14SSteve Longerbeam 
368685644a9bSPaul Elder 	if (enable) {
368785644a9bSPaul Elder 		ret = pm_runtime_resume_and_get(&sensor->i2c_client->dev);
368885644a9bSPaul Elder 		if (ret < 0)
368985644a9bSPaul Elder 			return ret;
369085644a9bSPaul Elder 
369185644a9bSPaul Elder 		ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
369285644a9bSPaul Elder 		if (ret) {
369385644a9bSPaul Elder 			pm_runtime_put(&sensor->i2c_client->dev);
369485644a9bSPaul Elder 			return ret;
369585644a9bSPaul Elder 		}
369685644a9bSPaul Elder 	}
369785644a9bSPaul Elder 
369819a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
369919a81c14SSteve Longerbeam 
370019a81c14SSteve Longerbeam 	if (sensor->streaming == !enable) {
370119a81c14SSteve Longerbeam 		if (enable && sensor->pending_mode_change) {
3702985cdcb0SHugues Fruchet 			ret = ov5640_set_mode(sensor);
370319a81c14SSteve Longerbeam 			if (ret)
370419a81c14SSteve Longerbeam 				goto out;
3705fb98e29fSHugues Fruchet 		}
3706e3ee691dSHugues Fruchet 
3707fb98e29fSHugues Fruchet 		if (enable && sensor->pending_fmt_change) {
3708e3ee691dSHugues Fruchet 			ret = ov5640_set_framefmt(sensor, &sensor->fmt);
3709e3ee691dSHugues Fruchet 			if (ret)
3710e3ee691dSHugues Fruchet 				goto out;
3711fb98e29fSHugues Fruchet 			sensor->pending_fmt_change = false;
371219a81c14SSteve Longerbeam 		}
371319a81c14SSteve Longerbeam 
37148e823f5cSJacopo Mondi 		if (ov5640_is_csi2(sensor))
3715f22996dbSHugues Fruchet 			ret = ov5640_set_stream_mipi(sensor, enable);
3716f22996dbSHugues Fruchet 		else
3717f22996dbSHugues Fruchet 			ret = ov5640_set_stream_dvp(sensor, enable);
3718f22996dbSHugues Fruchet 
371919a81c14SSteve Longerbeam 		if (!ret)
372019a81c14SSteve Longerbeam 			sensor->streaming = enable;
372119a81c14SSteve Longerbeam 	}
372285644a9bSPaul Elder 
372319a81c14SSteve Longerbeam out:
372419a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
372585644a9bSPaul Elder 
3726*e13064a3SAndrey Skvortsov 	if (!enable || ret) {
3727*e13064a3SAndrey Skvortsov 		pm_runtime_mark_last_busy(&sensor->i2c_client->dev);
372885644a9bSPaul Elder 		pm_runtime_put_autosuspend(&sensor->i2c_client->dev);
3729*e13064a3SAndrey Skvortsov 	}
373085644a9bSPaul Elder 
373119a81c14SSteve Longerbeam 	return ret;
373219a81c14SSteve Longerbeam }
373319a81c14SSteve Longerbeam 
373490b0f355SJacopo Mondi static int ov5640_init_cfg(struct v4l2_subdev *sd,
373590b0f355SJacopo Mondi 			   struct v4l2_subdev_state *state)
373690b0f355SJacopo Mondi {
373768453b02SGuoniu.zhou 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
373890b0f355SJacopo Mondi 	struct v4l2_mbus_framefmt *fmt =
373990b0f355SJacopo Mondi 				v4l2_subdev_get_try_format(sd, state, 0);
374066ed85ebSJacopo Mondi 	struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, state, 0);
374190b0f355SJacopo Mondi 
374268453b02SGuoniu.zhou 	*fmt = ov5640_is_csi2(sensor) ? ov5640_csi2_default_fmt :
374368453b02SGuoniu.zhou 					ov5640_dvp_default_fmt;
374490b0f355SJacopo Mondi 
374566ed85ebSJacopo Mondi 	crop->left = OV5640_PIXEL_ARRAY_LEFT;
374666ed85ebSJacopo Mondi 	crop->top = OV5640_PIXEL_ARRAY_TOP;
374766ed85ebSJacopo Mondi 	crop->width = OV5640_PIXEL_ARRAY_WIDTH;
374866ed85ebSJacopo Mondi 	crop->height = OV5640_PIXEL_ARRAY_HEIGHT;
374966ed85ebSJacopo Mondi 
375090b0f355SJacopo Mondi 	return 0;
375190b0f355SJacopo Mondi }
375290b0f355SJacopo Mondi 
375319a81c14SSteve Longerbeam static const struct v4l2_subdev_core_ops ov5640_core_ops = {
37542d18fbc5SAkinobu Mita 	.log_status = v4l2_ctrl_subdev_log_status,
37552d18fbc5SAkinobu Mita 	.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
37562d18fbc5SAkinobu Mita 	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
375719a81c14SSteve Longerbeam };
375819a81c14SSteve Longerbeam 
375919a81c14SSteve Longerbeam static const struct v4l2_subdev_video_ops ov5640_video_ops = {
376019a81c14SSteve Longerbeam 	.g_frame_interval = ov5640_g_frame_interval,
376119a81c14SSteve Longerbeam 	.s_frame_interval = ov5640_s_frame_interval,
376219a81c14SSteve Longerbeam 	.s_stream = ov5640_s_stream,
376319a81c14SSteve Longerbeam };
376419a81c14SSteve Longerbeam 
376519a81c14SSteve Longerbeam static const struct v4l2_subdev_pad_ops ov5640_pad_ops = {
376690b0f355SJacopo Mondi 	.init_cfg = ov5640_init_cfg,
376719a81c14SSteve Longerbeam 	.enum_mbus_code = ov5640_enum_mbus_code,
376819a81c14SSteve Longerbeam 	.get_fmt = ov5640_get_fmt,
376919a81c14SSteve Longerbeam 	.set_fmt = ov5640_set_fmt,
377066ed85ebSJacopo Mondi 	.get_selection = ov5640_get_selection,
377119a81c14SSteve Longerbeam 	.enum_frame_size = ov5640_enum_frame_size,
377219a81c14SSteve Longerbeam 	.enum_frame_interval = ov5640_enum_frame_interval,
377319a81c14SSteve Longerbeam };
377419a81c14SSteve Longerbeam 
377519a81c14SSteve Longerbeam static const struct v4l2_subdev_ops ov5640_subdev_ops = {
377619a81c14SSteve Longerbeam 	.core = &ov5640_core_ops,
377719a81c14SSteve Longerbeam 	.video = &ov5640_video_ops,
377819a81c14SSteve Longerbeam 	.pad = &ov5640_pad_ops,
377919a81c14SSteve Longerbeam };
378019a81c14SSteve Longerbeam 
378119a81c14SSteve Longerbeam static int ov5640_get_regulators(struct ov5640_dev *sensor)
378219a81c14SSteve Longerbeam {
378319a81c14SSteve Longerbeam 	int i;
378419a81c14SSteve Longerbeam 
378519a81c14SSteve Longerbeam 	for (i = 0; i < OV5640_NUM_SUPPLIES; i++)
378619a81c14SSteve Longerbeam 		sensor->supplies[i].supply = ov5640_supply_name[i];
378719a81c14SSteve Longerbeam 
378819a81c14SSteve Longerbeam 	return devm_regulator_bulk_get(&sensor->i2c_client->dev,
378919a81c14SSteve Longerbeam 				       OV5640_NUM_SUPPLIES,
379019a81c14SSteve Longerbeam 				       sensor->supplies);
379119a81c14SSteve Longerbeam }
379219a81c14SSteve Longerbeam 
37930f7acb52SHugues Fruchet static int ov5640_check_chip_id(struct ov5640_dev *sensor)
37940f7acb52SHugues Fruchet {
37950f7acb52SHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
37960f7acb52SHugues Fruchet 	int ret = 0;
37970f7acb52SHugues Fruchet 	u16 chip_id;
37980f7acb52SHugues Fruchet 
37990f7acb52SHugues Fruchet 	ret = ov5640_read_reg16(sensor, OV5640_REG_CHIP_ID, &chip_id);
38000f7acb52SHugues Fruchet 	if (ret) {
38010f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to read chip identifier\n",
38020f7acb52SHugues Fruchet 			__func__);
380385644a9bSPaul Elder 		return ret;
38040f7acb52SHugues Fruchet 	}
38050f7acb52SHugues Fruchet 
38060f7acb52SHugues Fruchet 	if (chip_id != 0x5640) {
38070f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: wrong chip identifier, expected 0x5640, got 0x%x\n",
38080f7acb52SHugues Fruchet 			__func__, chip_id);
380985644a9bSPaul Elder 		return -ENXIO;
38100f7acb52SHugues Fruchet 	}
38110f7acb52SHugues Fruchet 
381285644a9bSPaul Elder 	return 0;
38130f7acb52SHugues Fruchet }
38140f7acb52SHugues Fruchet 
3815e6714993SKieran Bingham static int ov5640_probe(struct i2c_client *client)
381619a81c14SSteve Longerbeam {
381719a81c14SSteve Longerbeam 	struct device *dev = &client->dev;
381819a81c14SSteve Longerbeam 	struct fwnode_handle *endpoint;
381919a81c14SSteve Longerbeam 	struct ov5640_dev *sensor;
382019a81c14SSteve Longerbeam 	int ret;
382119a81c14SSteve Longerbeam 
382219a81c14SSteve Longerbeam 	sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
382319a81c14SSteve Longerbeam 	if (!sensor)
382419a81c14SSteve Longerbeam 		return -ENOMEM;
382519a81c14SSteve Longerbeam 
382619a81c14SSteve Longerbeam 	sensor->i2c_client = client;
3827fb98e29fSHugues Fruchet 
3828fb98e29fSHugues Fruchet 	/*
3829fb98e29fSHugues Fruchet 	 * default init sequence initialize sensor to
3830fb98e29fSHugues Fruchet 	 * YUV422 UYVY VGA@30fps
3831fb98e29fSHugues Fruchet 	 */
383219a81c14SSteve Longerbeam 	sensor->frame_interval.numerator = 1;
383319a81c14SSteve Longerbeam 	sensor->frame_interval.denominator = ov5640_framerates[OV5640_30_FPS];
383419a81c14SSteve Longerbeam 	sensor->current_fr = OV5640_30_FPS;
383519a81c14SSteve Longerbeam 	sensor->current_mode =
3836086c25f8SMaxime Ripard 		&ov5640_mode_data[OV5640_MODE_VGA_640_480];
3837985cdcb0SHugues Fruchet 	sensor->last_mode = sensor->current_mode;
3838d7b41196SGuoniu.zhou 	sensor->current_link_freq =
3839d7b41196SGuoniu.zhou 		ov5640_csi2_link_freqs[OV5640_DEFAULT_LINK_FREQ];
384019a81c14SSteve Longerbeam 
384119a81c14SSteve Longerbeam 	sensor->ae_target = 52;
384219a81c14SSteve Longerbeam 
3843ce96bcf5SSakari Ailus 	endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev),
3844ce96bcf5SSakari Ailus 						  NULL);
384519a81c14SSteve Longerbeam 	if (!endpoint) {
384619a81c14SSteve Longerbeam 		dev_err(dev, "endpoint node not found\n");
384719a81c14SSteve Longerbeam 		return -EINVAL;
384819a81c14SSteve Longerbeam 	}
384919a81c14SSteve Longerbeam 
385019a81c14SSteve Longerbeam 	ret = v4l2_fwnode_endpoint_parse(endpoint, &sensor->ep);
385119a81c14SSteve Longerbeam 	fwnode_handle_put(endpoint);
385219a81c14SSteve Longerbeam 	if (ret) {
385319a81c14SSteve Longerbeam 		dev_err(dev, "Could not parse endpoint\n");
385419a81c14SSteve Longerbeam 		return ret;
385519a81c14SSteve Longerbeam 	}
385619a81c14SSteve Longerbeam 
38572c61e48dSLad Prabhakar 	if (sensor->ep.bus_type != V4L2_MBUS_PARALLEL &&
38582c61e48dSLad Prabhakar 	    sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY &&
38592c61e48dSLad Prabhakar 	    sensor->ep.bus_type != V4L2_MBUS_BT656) {
38602c61e48dSLad Prabhakar 		dev_err(dev, "Unsupported bus type %d\n", sensor->ep.bus_type);
38612c61e48dSLad Prabhakar 		return -EINVAL;
38622c61e48dSLad Prabhakar 	}
38632c61e48dSLad Prabhakar 
386468453b02SGuoniu.zhou 	sensor->fmt = ov5640_is_csi2(sensor) ? ov5640_csi2_default_fmt :
386568453b02SGuoniu.zhou 					       ov5640_dvp_default_fmt;
386668453b02SGuoniu.zhou 
386719a81c14SSteve Longerbeam 	/* get system clock (xclk) */
386819a81c14SSteve Longerbeam 	sensor->xclk = devm_clk_get(dev, "xclk");
386919a81c14SSteve Longerbeam 	if (IS_ERR(sensor->xclk)) {
387019a81c14SSteve Longerbeam 		dev_err(dev, "failed to get xclk\n");
387119a81c14SSteve Longerbeam 		return PTR_ERR(sensor->xclk);
387219a81c14SSteve Longerbeam 	}
387319a81c14SSteve Longerbeam 
387419a81c14SSteve Longerbeam 	sensor->xclk_freq = clk_get_rate(sensor->xclk);
387519a81c14SSteve Longerbeam 	if (sensor->xclk_freq < OV5640_XCLK_MIN ||
387619a81c14SSteve Longerbeam 	    sensor->xclk_freq > OV5640_XCLK_MAX) {
387719a81c14SSteve Longerbeam 		dev_err(dev, "xclk frequency out of range: %d Hz\n",
387819a81c14SSteve Longerbeam 			sensor->xclk_freq);
387919a81c14SSteve Longerbeam 		return -EINVAL;
388019a81c14SSteve Longerbeam 	}
388119a81c14SSteve Longerbeam 
388219a81c14SSteve Longerbeam 	/* request optional power down pin */
388319a81c14SSteve Longerbeam 	sensor->pwdn_gpio = devm_gpiod_get_optional(dev, "powerdown",
388419a81c14SSteve Longerbeam 						    GPIOD_OUT_HIGH);
38858791a102SFabio Estevam 	if (IS_ERR(sensor->pwdn_gpio))
38868791a102SFabio Estevam 		return PTR_ERR(sensor->pwdn_gpio);
38878791a102SFabio Estevam 
388819a81c14SSteve Longerbeam 	/* request optional reset pin */
388919a81c14SSteve Longerbeam 	sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset",
389019a81c14SSteve Longerbeam 						     GPIOD_OUT_HIGH);
38918791a102SFabio Estevam 	if (IS_ERR(sensor->reset_gpio))
38928791a102SFabio Estevam 		return PTR_ERR(sensor->reset_gpio);
389319a81c14SSteve Longerbeam 
389419a81c14SSteve Longerbeam 	v4l2_i2c_subdev_init(&sensor->sd, client, &ov5640_subdev_ops);
389519a81c14SSteve Longerbeam 
38962d18fbc5SAkinobu Mita 	sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
38972d18fbc5SAkinobu Mita 			    V4L2_SUBDEV_FL_HAS_EVENTS;
389819a81c14SSteve Longerbeam 	sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
389919a81c14SSteve Longerbeam 	sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
390019a81c14SSteve Longerbeam 	ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
390119a81c14SSteve Longerbeam 	if (ret)
390219a81c14SSteve Longerbeam 		return ret;
390319a81c14SSteve Longerbeam 
390419a81c14SSteve Longerbeam 	ret = ov5640_get_regulators(sensor);
390519a81c14SSteve Longerbeam 	if (ret)
390685644a9bSPaul Elder 		goto entity_cleanup;
390719a81c14SSteve Longerbeam 
390819a81c14SSteve Longerbeam 	mutex_init(&sensor->lock);
390919a81c14SSteve Longerbeam 
391019a81c14SSteve Longerbeam 	ret = ov5640_init_controls(sensor);
391119a81c14SSteve Longerbeam 	if (ret)
391219a81c14SSteve Longerbeam 		goto entity_cleanup;
391319a81c14SSteve Longerbeam 
391485644a9bSPaul Elder 	ret = ov5640_sensor_resume(dev);
391585644a9bSPaul Elder 	if (ret) {
391685644a9bSPaul Elder 		dev_err(dev, "failed to power on\n");
391785644a9bSPaul Elder 		goto entity_cleanup;
391885644a9bSPaul Elder 	}
391985644a9bSPaul Elder 
392085644a9bSPaul Elder 	pm_runtime_set_active(dev);
392185644a9bSPaul Elder 	pm_runtime_get_noresume(dev);
392285644a9bSPaul Elder 	pm_runtime_enable(dev);
392385644a9bSPaul Elder 
392485644a9bSPaul Elder 	ret = ov5640_check_chip_id(sensor);
392585644a9bSPaul Elder 	if (ret)
392685644a9bSPaul Elder 		goto err_pm_runtime;
392785644a9bSPaul Elder 
392815786f7bSSakari Ailus 	ret = v4l2_async_register_subdev_sensor(&sensor->sd);
392919a81c14SSteve Longerbeam 	if (ret)
393085644a9bSPaul Elder 		goto err_pm_runtime;
393185644a9bSPaul Elder 
393285644a9bSPaul Elder 	pm_runtime_set_autosuspend_delay(dev, 1000);
393385644a9bSPaul Elder 	pm_runtime_use_autosuspend(dev);
3934*e13064a3SAndrey Skvortsov 	pm_runtime_mark_last_busy(dev);
393585644a9bSPaul Elder 	pm_runtime_put_autosuspend(dev);
393619a81c14SSteve Longerbeam 
393719a81c14SSteve Longerbeam 	return 0;
393819a81c14SSteve Longerbeam 
393985644a9bSPaul Elder err_pm_runtime:
394085644a9bSPaul Elder 	pm_runtime_put_noidle(dev);
394185644a9bSPaul Elder 	pm_runtime_disable(dev);
394219a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
394385644a9bSPaul Elder 	ov5640_sensor_suspend(dev);
394419a81c14SSteve Longerbeam entity_cleanup:
394519a81c14SSteve Longerbeam 	media_entity_cleanup(&sensor->sd.entity);
3946bfcba38dSTomi Valkeinen 	mutex_destroy(&sensor->lock);
394719a81c14SSteve Longerbeam 	return ret;
394819a81c14SSteve Longerbeam }
394919a81c14SSteve Longerbeam 
3950ed5c2f5fSUwe Kleine-König static void ov5640_remove(struct i2c_client *client)
395119a81c14SSteve Longerbeam {
395219a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
395319a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
395485644a9bSPaul Elder 	struct device *dev = &client->dev;
395585644a9bSPaul Elder 
395685644a9bSPaul Elder 	pm_runtime_disable(dev);
395785644a9bSPaul Elder 	if (!pm_runtime_status_suspended(dev))
395885644a9bSPaul Elder 		ov5640_sensor_suspend(dev);
395985644a9bSPaul Elder 	pm_runtime_set_suspended(dev);
396019a81c14SSteve Longerbeam 
396119a81c14SSteve Longerbeam 	v4l2_async_unregister_subdev(&sensor->sd);
396219a81c14SSteve Longerbeam 	media_entity_cleanup(&sensor->sd.entity);
396319a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
3964bfcba38dSTomi Valkeinen 	mutex_destroy(&sensor->lock);
396519a81c14SSteve Longerbeam }
396619a81c14SSteve Longerbeam 
396785644a9bSPaul Elder static const struct dev_pm_ops ov5640_pm_ops = {
396885644a9bSPaul Elder 	SET_RUNTIME_PM_OPS(ov5640_sensor_suspend, ov5640_sensor_resume, NULL)
396985644a9bSPaul Elder };
397085644a9bSPaul Elder 
397119a81c14SSteve Longerbeam static const struct i2c_device_id ov5640_id[] = {
397219a81c14SSteve Longerbeam 	{"ov5640", 0},
397319a81c14SSteve Longerbeam 	{},
397419a81c14SSteve Longerbeam };
397519a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(i2c, ov5640_id);
397619a81c14SSteve Longerbeam 
397719a81c14SSteve Longerbeam static const struct of_device_id ov5640_dt_ids[] = {
397819a81c14SSteve Longerbeam 	{ .compatible = "ovti,ov5640" },
397919a81c14SSteve Longerbeam 	{ /* sentinel */ }
398019a81c14SSteve Longerbeam };
398119a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(of, ov5640_dt_ids);
398219a81c14SSteve Longerbeam 
398319a81c14SSteve Longerbeam static struct i2c_driver ov5640_i2c_driver = {
398419a81c14SSteve Longerbeam 	.driver = {
398519a81c14SSteve Longerbeam 		.name  = "ov5640",
398619a81c14SSteve Longerbeam 		.of_match_table	= ov5640_dt_ids,
398785644a9bSPaul Elder 		.pm = &ov5640_pm_ops,
398819a81c14SSteve Longerbeam 	},
398919a81c14SSteve Longerbeam 	.id_table = ov5640_id,
3990e6714993SKieran Bingham 	.probe_new = ov5640_probe,
399119a81c14SSteve Longerbeam 	.remove   = ov5640_remove,
399219a81c14SSteve Longerbeam };
399319a81c14SSteve Longerbeam 
399419a81c14SSteve Longerbeam module_i2c_driver(ov5640_i2c_driver);
399519a81c14SSteve Longerbeam 
399619a81c14SSteve Longerbeam MODULE_DESCRIPTION("OV5640 MIPI Camera Subdev Driver");
399719a81c14SSteve Longerbeam MODULE_LICENSE("GPL");
3998