xref: /openbmc/linux/drivers/media/i2c/ov5640.c (revision b6ae5022)
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>
1841d8d7f5SHugues Fruchet #include <linux/regulator/consumer.h>
1919a81c14SSteve Longerbeam #include <linux/slab.h>
2019a81c14SSteve Longerbeam #include <linux/types.h>
2119a81c14SSteve Longerbeam #include <media/v4l2-async.h>
2219a81c14SSteve Longerbeam #include <media/v4l2-ctrls.h>
2319a81c14SSteve Longerbeam #include <media/v4l2-device.h>
242d18fbc5SAkinobu Mita #include <media/v4l2-event.h>
2519a81c14SSteve Longerbeam #include <media/v4l2-fwnode.h>
2619a81c14SSteve Longerbeam #include <media/v4l2-subdev.h>
2719a81c14SSteve Longerbeam 
2819a81c14SSteve Longerbeam /* min/typical/max system clock (xclk) frequencies */
2919a81c14SSteve Longerbeam #define OV5640_XCLK_MIN  6000000
3041cb1c73SPhilipp Puschmann #define OV5640_XCLK_MAX 54000000
3119a81c14SSteve Longerbeam 
325113d5b3SJacopo Mondi #define OV5640_NATIVE_WIDTH		2624
335113d5b3SJacopo Mondi #define OV5640_NATIVE_HEIGHT		1964
345113d5b3SJacopo Mondi #define OV5640_PIXEL_ARRAY_TOP		14
355113d5b3SJacopo Mondi #define OV5640_PIXEL_ARRAY_LEFT		16
365113d5b3SJacopo Mondi #define OV5640_PIXEL_ARRAY_WIDTH	2592
375113d5b3SJacopo Mondi #define OV5640_PIXEL_ARRAY_HEIGHT	1944
385113d5b3SJacopo Mondi 
39bce93b82SJacopo Mondi /* FIXME: not documented. */
40bce93b82SJacopo Mondi #define OV5640_MIN_VBLANK	24
41bce93b82SJacopo Mondi #define OV5640_MAX_VTS		3375
42bce93b82SJacopo Mondi 
4319a81c14SSteve Longerbeam #define OV5640_DEFAULT_SLAVE_ID 0x3c
4419a81c14SSteve Longerbeam 
453c28588fSJacopo Mondi #define OV5640_LINK_RATE_MAX		490000000U
463c28588fSJacopo Mondi 
47d47c4126SHugues Fruchet #define OV5640_REG_SYS_RESET02		0x3002
48d47c4126SHugues Fruchet #define OV5640_REG_SYS_CLOCK_ENABLE02	0x3006
49f22996dbSHugues Fruchet #define OV5640_REG_SYS_CTRL0		0x3008
503b987d70SLad Prabhakar #define OV5640_REG_SYS_CTRL0_SW_PWDN	0x42
513b987d70SLad Prabhakar #define OV5640_REG_SYS_CTRL0_SW_PWUP	0x02
5219a81c14SSteve Longerbeam #define OV5640_REG_CHIP_ID		0x300a
53f22996dbSHugues Fruchet #define OV5640_REG_IO_MIPI_CTRL00	0x300e
54f22996dbSHugues Fruchet #define OV5640_REG_PAD_OUTPUT_ENABLE01	0x3017
55f22996dbSHugues Fruchet #define OV5640_REG_PAD_OUTPUT_ENABLE02	0x3018
5619a81c14SSteve Longerbeam #define OV5640_REG_PAD_OUTPUT00		0x3019
57f22996dbSHugues Fruchet #define OV5640_REG_SYSTEM_CONTROL1	0x302e
5819a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL0		0x3034
5919a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL1		0x3035
6019a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL2		0x3036
6119a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL3		0x3037
6219a81c14SSteve Longerbeam #define OV5640_REG_SLAVE_ID		0x3100
63f22996dbSHugues Fruchet #define OV5640_REG_SCCB_SYS_CTRL1	0x3103
6419a81c14SSteve Longerbeam #define OV5640_REG_SYS_ROOT_DIVIDER	0x3108
6519a81c14SSteve Longerbeam #define OV5640_REG_AWB_R_GAIN		0x3400
6619a81c14SSteve Longerbeam #define OV5640_REG_AWB_G_GAIN		0x3402
6719a81c14SSteve Longerbeam #define OV5640_REG_AWB_B_GAIN		0x3404
6819a81c14SSteve Longerbeam #define OV5640_REG_AWB_MANUAL_CTRL	0x3406
6919a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_HI	0x3500
7019a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_MED	0x3501
7119a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_LO	0x3502
7219a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_MANUAL	0x3503
7319a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_REAL_GAIN	0x350a
7419a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_VTS		0x350c
753145efcdSJacopo Mondi #define OV5640_REG_TIMING_HS		0x3800
763145efcdSJacopo Mondi #define OV5640_REG_TIMING_VS		0x3802
773145efcdSJacopo Mondi #define OV5640_REG_TIMING_HW		0x3804
783145efcdSJacopo Mondi #define OV5640_REG_TIMING_VH		0x3806
7986633417SMaxime Ripard #define OV5640_REG_TIMING_DVPHO		0x3808
8086633417SMaxime Ripard #define OV5640_REG_TIMING_DVPVO		0x380a
8119a81c14SSteve Longerbeam #define OV5640_REG_TIMING_HTS		0x380c
8219a81c14SSteve Longerbeam #define OV5640_REG_TIMING_VTS		0x380e
833145efcdSJacopo Mondi #define OV5640_REG_TIMING_HOFFS		0x3810
843145efcdSJacopo Mondi #define OV5640_REG_TIMING_VOFFS		0x3812
85ce85705aSHugues Fruchet #define OV5640_REG_TIMING_TC_REG20	0x3820
8619a81c14SSteve Longerbeam #define OV5640_REG_TIMING_TC_REG21	0x3821
8719a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL00		0x3a00
8819a81c14SSteve Longerbeam #define OV5640_REG_AEC_B50_STEP		0x3a08
8919a81c14SSteve Longerbeam #define OV5640_REG_AEC_B60_STEP		0x3a0a
9019a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0D		0x3a0d
9119a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0E		0x3a0e
9219a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0F		0x3a0f
9319a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL10		0x3a10
9419a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL11		0x3a11
9519a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1B		0x3a1b
9619a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1E		0x3a1e
9719a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1F		0x3a1f
9819a81c14SSteve Longerbeam #define OV5640_REG_HZ5060_CTRL00	0x3c00
9919a81c14SSteve Longerbeam #define OV5640_REG_HZ5060_CTRL01	0x3c01
10019a81c14SSteve Longerbeam #define OV5640_REG_SIGMADELTA_CTRL0C	0x3c0c
10119a81c14SSteve Longerbeam #define OV5640_REG_FRAME_CTRL01		0x4202
102e3ee691dSHugues Fruchet #define OV5640_REG_FORMAT_CONTROL00	0x4300
1037cb013b1SChen-Yu Tsai #define OV5640_REG_VFIFO_HSIZE		0x4602
1047cb013b1SChen-Yu Tsai #define OV5640_REG_VFIFO_VSIZE		0x4604
1052b5c18f9SChen-Yu Tsai #define OV5640_REG_JPG_MODE_SELECT	0x4713
1064039b037SLad Prabhakar #define OV5640_REG_CCIR656_CTRL00	0x4730
107f22996dbSHugues Fruchet #define OV5640_REG_POLARITY_CTRL00	0x4740
10819a81c14SSteve Longerbeam #define OV5640_REG_MIPI_CTRL00		0x4800
10919a81c14SSteve Longerbeam #define OV5640_REG_DEBUG_MODE		0x4814
1106c957ed7SJacopo Mondi #define OV5640_REG_PCLK_PERIOD		0x4837
111e3ee691dSHugues Fruchet #define OV5640_REG_ISP_FORMAT_MUX_CTRL	0x501f
11219a81c14SSteve Longerbeam #define OV5640_REG_PRE_ISP_TEST_SET1	0x503d
11319a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL0		0x5580
11419a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL1		0x5581
11519a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL3		0x5583
11619a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL4		0x5584
11719a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL5		0x5585
11819a81c14SSteve Longerbeam #define OV5640_REG_AVG_READOUT		0x56a1
11919a81c14SSteve Longerbeam 
12019a81c14SSteve Longerbeam enum ov5640_mode_id {
12132ea5e05SHugues Fruchet 	OV5640_MODE_QQVGA_160_120 = 0,
12232ea5e05SHugues Fruchet 	OV5640_MODE_QCIF_176_144,
12319a81c14SSteve Longerbeam 	OV5640_MODE_QVGA_320_240,
12419a81c14SSteve Longerbeam 	OV5640_MODE_VGA_640_480,
12519a81c14SSteve Longerbeam 	OV5640_MODE_NTSC_720_480,
12619a81c14SSteve Longerbeam 	OV5640_MODE_PAL_720_576,
12719a81c14SSteve Longerbeam 	OV5640_MODE_XGA_1024_768,
12819a81c14SSteve Longerbeam 	OV5640_MODE_720P_1280_720,
12919a81c14SSteve Longerbeam 	OV5640_MODE_1080P_1920_1080,
13019a81c14SSteve Longerbeam 	OV5640_MODE_QSXGA_2592_1944,
13119a81c14SSteve Longerbeam 	OV5640_NUM_MODES,
13219a81c14SSteve Longerbeam };
13319a81c14SSteve Longerbeam 
13419a81c14SSteve Longerbeam enum ov5640_frame_rate {
13519a81c14SSteve Longerbeam 	OV5640_15_FPS = 0,
13619a81c14SSteve Longerbeam 	OV5640_30_FPS,
137e823fb16SMaxime Ripard 	OV5640_60_FPS,
13819a81c14SSteve Longerbeam 	OV5640_NUM_FRAMERATES,
13919a81c14SSteve Longerbeam };
14019a81c14SSteve Longerbeam 
14122845bf2SJacopo Mondi enum ov5640_pixel_rate_id {
14222845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_168M,
14322845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_148M,
14422845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_124M,
14522845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_96M,
14622845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_48M,
14722845bf2SJacopo Mondi 	OV5640_NUM_PIXEL_RATES,
14822845bf2SJacopo Mondi };
14922845bf2SJacopo Mondi 
15022845bf2SJacopo Mondi /*
15122845bf2SJacopo Mondi  * The chip manual suggests 24/48/96/192 MHz pixel clocks.
15222845bf2SJacopo Mondi  *
15322845bf2SJacopo Mondi  * 192MHz exceeds the sysclk limits; use 168MHz as maximum pixel rate for
15422845bf2SJacopo Mondi  * full resolution mode @15 FPS.
15522845bf2SJacopo Mondi  */
15622845bf2SJacopo Mondi static const u32 ov5640_pixel_rates[] = {
15722845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_168M] = 168000000,
15822845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_148M] = 148000000,
15922845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_124M] = 124000000,
16022845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_96M] = 96000000,
16122845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_48M] = 48000000,
16222845bf2SJacopo Mondi };
16322845bf2SJacopo Mondi 
1647a3b8d4bSJacopo Mondi /*
1657a3b8d4bSJacopo Mondi  * MIPI CSI-2 link frequencies.
1667a3b8d4bSJacopo Mondi  *
1677a3b8d4bSJacopo Mondi  * Derived from the above defined pixel rate for bpp = (8, 16, 24) and
1687a3b8d4bSJacopo Mondi  * data_lanes = (1, 2)
1697a3b8d4bSJacopo Mondi  *
1707a3b8d4bSJacopo Mondi  * link_freq = (pixel_rate * bpp) / (2 * data_lanes)
1717a3b8d4bSJacopo Mondi  */
1727a3b8d4bSJacopo Mondi static const s64 ov5640_csi2_link_freqs[] = {
1737a3b8d4bSJacopo Mondi 	992000000, 888000000, 768000000, 744000000, 672000000, 672000000,
1747a3b8d4bSJacopo Mondi 	592000000, 592000000, 576000000, 576000000, 496000000, 496000000,
1757a3b8d4bSJacopo Mondi 	384000000, 384000000, 384000000, 336000000, 296000000, 288000000,
1767a3b8d4bSJacopo Mondi 	248000000, 192000000, 192000000, 192000000, 96000000,
1777a3b8d4bSJacopo Mondi };
1787a3b8d4bSJacopo Mondi 
1797a3b8d4bSJacopo Mondi /* Link freq for default mode: UYVY 16 bpp, 2 data lanes. */
1807a3b8d4bSJacopo Mondi #define OV5640_DEFAULT_LINK_FREQ	13
1817a3b8d4bSJacopo Mondi 
182b7ed3abdSLoic Poulain enum ov5640_format_mux {
183b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_YUV422 = 0,
184b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_RGB,
185b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_DITHER,
186b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_RAW_DPC,
187b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_SNR_RAW,
188b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_RAW_CIP,
189b7ed3abdSLoic Poulain };
190b7ed3abdSLoic Poulain 
1912d7671f6SJacopo Mondi static const struct ov5640_pixfmt {
192e3ee691dSHugues Fruchet 	u32 code;
193e3ee691dSHugues Fruchet 	u32 colorspace;
1942d7671f6SJacopo Mondi 	u8 bpp;
1952d7671f6SJacopo Mondi } ov5640_formats[] = {
1962d7671f6SJacopo Mondi 	{
1972d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_JPEG_1X8,
1982d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_JPEG,
1992d7671f6SJacopo Mondi 		.bpp = 16,
2002d7671f6SJacopo Mondi 	}, {
2012d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_UYVY8_2X8,
2022d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2032d7671f6SJacopo Mondi 		.bpp = 16,
2042d7671f6SJacopo Mondi 	}, {
2052d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_UYVY8_1X16,
2062d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2072d7671f6SJacopo Mondi 		.bpp = 16,
2082d7671f6SJacopo Mondi 	}, {
2092d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_YUYV8_2X8,
2102d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2112d7671f6SJacopo Mondi 		.bpp = 16,
2122d7671f6SJacopo Mondi 	}, {
2132d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_YUYV8_1X16,
2142d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2152d7671f6SJacopo Mondi 		.bpp = 16,
2162d7671f6SJacopo Mondi 	}, {
2172d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_RGB565_2X8_LE,
2182d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2192d7671f6SJacopo Mondi 		.bpp = 16,
2202d7671f6SJacopo Mondi 	}, {
2212d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_RGB565_2X8_BE,
2222d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2232d7671f6SJacopo Mondi 		.bpp = 16,
2242d7671f6SJacopo Mondi 	}, {
2252d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_SBGGR8_1X8,
2262d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2272d7671f6SJacopo Mondi 		.bpp = 8,
2282d7671f6SJacopo Mondi 	}, {
2292d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_SGBRG8_1X8,
2302d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2312d7671f6SJacopo Mondi 		.bpp = 8
2322d7671f6SJacopo Mondi 	}, {
2332d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_SGRBG8_1X8,
2342d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2352d7671f6SJacopo Mondi 		.bpp = 8,
2362d7671f6SJacopo Mondi 	}, {
2372d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_SRGGB8_1X8,
2382d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2392d7671f6SJacopo Mondi 		.bpp = 8,
2402d7671f6SJacopo Mondi 	},
241e3ee691dSHugues Fruchet };
242e3ee691dSHugues Fruchet 
2433c28588fSJacopo Mondi static u32 ov5640_code_to_bpp(u32 code)
2443c28588fSJacopo Mondi {
2453c28588fSJacopo Mondi 	unsigned int i;
2463c28588fSJacopo Mondi 
2473c28588fSJacopo Mondi 	for (i = 0; i < ARRAY_SIZE(ov5640_formats); ++i) {
2483c28588fSJacopo Mondi 		if (ov5640_formats[i].code == code)
2493c28588fSJacopo Mondi 			return ov5640_formats[i].bpp;
2503c28588fSJacopo Mondi 	}
2513c28588fSJacopo Mondi 
2523c28588fSJacopo Mondi 	return 0;
2533c28588fSJacopo Mondi }
2543c28588fSJacopo Mondi 
25519a81c14SSteve Longerbeam /*
25619a81c14SSteve Longerbeam  * FIXME: remove this when a subdev API becomes available
25719a81c14SSteve Longerbeam  * to set the MIPI CSI-2 virtual channel.
25819a81c14SSteve Longerbeam  */
25919a81c14SSteve Longerbeam static unsigned int virtual_channel;
2608670d70aSHugues Fruchet module_param(virtual_channel, uint, 0444);
26119a81c14SSteve Longerbeam MODULE_PARM_DESC(virtual_channel,
26219a81c14SSteve Longerbeam 		 "MIPI CSI-2 virtual channel (0..3), default 0");
26319a81c14SSteve Longerbeam 
26419a81c14SSteve Longerbeam static const int ov5640_framerates[] = {
26519a81c14SSteve Longerbeam 	[OV5640_15_FPS] = 15,
26619a81c14SSteve Longerbeam 	[OV5640_30_FPS] = 30,
267e823fb16SMaxime Ripard 	[OV5640_60_FPS] = 60,
26819a81c14SSteve Longerbeam };
26919a81c14SSteve Longerbeam 
27019a81c14SSteve Longerbeam /* regulator supplies */
27119a81c14SSteve Longerbeam static const char * const ov5640_supply_name[] = {
27241d8d7f5SHugues Fruchet 	"DOVDD", /* Digital I/O (1.8V) supply */
27319a81c14SSteve Longerbeam 	"AVDD",  /* Analog (2.8V) supply */
27424c8ac89SFabio Estevam 	"DVDD",  /* Digital Core (1.5V) supply */
27519a81c14SSteve Longerbeam };
27619a81c14SSteve Longerbeam 
27719a81c14SSteve Longerbeam #define OV5640_NUM_SUPPLIES ARRAY_SIZE(ov5640_supply_name)
27819a81c14SSteve Longerbeam 
27919a81c14SSteve Longerbeam /*
28019a81c14SSteve Longerbeam  * Image size under 1280 * 960 are SUBSAMPLING
28119a81c14SSteve Longerbeam  * Image size upper 1280 * 960 are SCALING
28219a81c14SSteve Longerbeam  */
28319a81c14SSteve Longerbeam enum ov5640_downsize_mode {
28419a81c14SSteve Longerbeam 	SUBSAMPLING,
28519a81c14SSteve Longerbeam 	SCALING,
28619a81c14SSteve Longerbeam };
28719a81c14SSteve Longerbeam 
28819a81c14SSteve Longerbeam struct reg_value {
28919a81c14SSteve Longerbeam 	u16 reg_addr;
29019a81c14SSteve Longerbeam 	u8 val;
29119a81c14SSteve Longerbeam 	u8 mask;
29219a81c14SSteve Longerbeam 	u32 delay_ms;
29319a81c14SSteve Longerbeam };
29419a81c14SSteve Longerbeam 
2955113d5b3SJacopo Mondi struct ov5640_timings {
2963145efcdSJacopo Mondi 	/* Analog crop rectangle. */
2973145efcdSJacopo Mondi 	struct v4l2_rect analog_crop;
2983145efcdSJacopo Mondi 	/* Visibile crop: from analog crop top-left corner. */
2993145efcdSJacopo Mondi 	struct v4l2_rect crop;
3005113d5b3SJacopo Mondi 	/* Total pixels per line: width + fixed hblank. */
301476dec01SMaxime Ripard 	u32 htot;
3025113d5b3SJacopo Mondi 	/* Default vertical blanking: frame height = height + vblank. */
3033145efcdSJacopo Mondi 	u32 vblank_def;
3045113d5b3SJacopo Mondi };
3055113d5b3SJacopo Mondi 
3065113d5b3SJacopo Mondi struct ov5640_mode_info {
3075113d5b3SJacopo Mondi 	enum ov5640_mode_id id;
3085113d5b3SJacopo Mondi 	enum ov5640_downsize_mode dn_mode;
3095113d5b3SJacopo Mondi 	enum ov5640_pixel_rate_id pixel_rate;
3105113d5b3SJacopo Mondi 
3115113d5b3SJacopo Mondi 	unsigned int width;
3125113d5b3SJacopo Mondi 	unsigned int height;
3135113d5b3SJacopo Mondi 
3145113d5b3SJacopo Mondi 	struct ov5640_timings dvp_timings;
3155113d5b3SJacopo Mondi 	struct ov5640_timings csi2_timings;
3165113d5b3SJacopo Mondi 
31719a81c14SSteve Longerbeam 	const struct reg_value *reg_data;
31819a81c14SSteve Longerbeam 	u32 reg_data_size;
3195113d5b3SJacopo Mondi 
3205113d5b3SJacopo Mondi 	/* Used by s_frame_interval only. */
3215554c80eSAdam Ford 	u32 max_fps;
32219f2e3e6SHugues Fruchet 	u32 def_fps;
32319a81c14SSteve Longerbeam };
32419a81c14SSteve Longerbeam 
32519a81c14SSteve Longerbeam struct ov5640_ctrls {
32619a81c14SSteve Longerbeam 	struct v4l2_ctrl_handler handler;
327cc196e48SBenoit Parrot 	struct v4l2_ctrl *pixel_rate;
3287a3b8d4bSJacopo Mondi 	struct v4l2_ctrl *link_freq;
32932979f67SJacopo Mondi 	struct v4l2_ctrl *hblank;
330bce93b82SJacopo Mondi 	struct v4l2_ctrl *vblank;
33119a81c14SSteve Longerbeam 	struct {
33219a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_exp;
33319a81c14SSteve Longerbeam 		struct v4l2_ctrl *exposure;
33419a81c14SSteve Longerbeam 	};
33519a81c14SSteve Longerbeam 	struct {
33619a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_wb;
33719a81c14SSteve Longerbeam 		struct v4l2_ctrl *blue_balance;
33819a81c14SSteve Longerbeam 		struct v4l2_ctrl *red_balance;
33919a81c14SSteve Longerbeam 	};
34019a81c14SSteve Longerbeam 	struct {
34119a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_gain;
34219a81c14SSteve Longerbeam 		struct v4l2_ctrl *gain;
34319a81c14SSteve Longerbeam 	};
34419a81c14SSteve Longerbeam 	struct v4l2_ctrl *brightness;
3451068fecaSMylène Josserand 	struct v4l2_ctrl *light_freq;
34619a81c14SSteve Longerbeam 	struct v4l2_ctrl *saturation;
34719a81c14SSteve Longerbeam 	struct v4l2_ctrl *contrast;
34819a81c14SSteve Longerbeam 	struct v4l2_ctrl *hue;
34919a81c14SSteve Longerbeam 	struct v4l2_ctrl *test_pattern;
350ce85705aSHugues Fruchet 	struct v4l2_ctrl *hflip;
351ce85705aSHugues Fruchet 	struct v4l2_ctrl *vflip;
35219a81c14SSteve Longerbeam };
35319a81c14SSteve Longerbeam 
35419a81c14SSteve Longerbeam struct ov5640_dev {
35519a81c14SSteve Longerbeam 	struct i2c_client *i2c_client;
35619a81c14SSteve Longerbeam 	struct v4l2_subdev sd;
35719a81c14SSteve Longerbeam 	struct media_pad pad;
35819a81c14SSteve Longerbeam 	struct v4l2_fwnode_endpoint ep; /* the parsed DT endpoint info */
35919a81c14SSteve Longerbeam 	struct clk *xclk; /* system clock to OV5640 */
36019a81c14SSteve Longerbeam 	u32 xclk_freq;
36119a81c14SSteve Longerbeam 
36219a81c14SSteve Longerbeam 	struct regulator_bulk_data supplies[OV5640_NUM_SUPPLIES];
36319a81c14SSteve Longerbeam 	struct gpio_desc *reset_gpio;
36419a81c14SSteve Longerbeam 	struct gpio_desc *pwdn_gpio;
365c3f3ba3eSHugues Fruchet 	bool   upside_down;
36619a81c14SSteve Longerbeam 
36719a81c14SSteve Longerbeam 	/* lock to protect all members below */
36819a81c14SSteve Longerbeam 	struct mutex lock;
36919a81c14SSteve Longerbeam 
37019a81c14SSteve Longerbeam 	int power_count;
37119a81c14SSteve Longerbeam 
37219a81c14SSteve Longerbeam 	struct v4l2_mbus_framefmt fmt;
373fb98e29fSHugues Fruchet 	bool pending_fmt_change;
37419a81c14SSteve Longerbeam 
37519a81c14SSteve Longerbeam 	const struct ov5640_mode_info *current_mode;
376985cdcb0SHugues Fruchet 	const struct ov5640_mode_info *last_mode;
37719a81c14SSteve Longerbeam 	enum ov5640_frame_rate current_fr;
37819a81c14SSteve Longerbeam 	struct v4l2_fract frame_interval;
3793c28588fSJacopo Mondi 	s64 current_link_freq;
38019a81c14SSteve Longerbeam 
38119a81c14SSteve Longerbeam 	struct ov5640_ctrls ctrls;
38219a81c14SSteve Longerbeam 
38319a81c14SSteve Longerbeam 	u32 prev_sysclk, prev_hts;
38419a81c14SSteve Longerbeam 	u32 ae_low, ae_high, ae_target;
38519a81c14SSteve Longerbeam 
38619a81c14SSteve Longerbeam 	bool pending_mode_change;
38719a81c14SSteve Longerbeam 	bool streaming;
38819a81c14SSteve Longerbeam };
38919a81c14SSteve Longerbeam 
39019a81c14SSteve Longerbeam static inline struct ov5640_dev *to_ov5640_dev(struct v4l2_subdev *sd)
39119a81c14SSteve Longerbeam {
39219a81c14SSteve Longerbeam 	return container_of(sd, struct ov5640_dev, sd);
39319a81c14SSteve Longerbeam }
39419a81c14SSteve Longerbeam 
39519a81c14SSteve Longerbeam static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
39619a81c14SSteve Longerbeam {
39719a81c14SSteve Longerbeam 	return &container_of(ctrl->handler, struct ov5640_dev,
39819a81c14SSteve Longerbeam 			     ctrls.handler)->sd;
39919a81c14SSteve Longerbeam }
40019a81c14SSteve Longerbeam 
4018e823f5cSJacopo Mondi static inline bool ov5640_is_csi2(const struct ov5640_dev *sensor)
4028e823f5cSJacopo Mondi {
4038e823f5cSJacopo Mondi 	return sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY;
4048e823f5cSJacopo Mondi }
4058e823f5cSJacopo Mondi 
40619a81c14SSteve Longerbeam /*
40719a81c14SSteve Longerbeam  * FIXME: all of these register tables are likely filled with
40819a81c14SSteve Longerbeam  * entries that set the register to their power-on default values,
40919a81c14SSteve Longerbeam  * and which are otherwise not touched by this driver. Those entries
41019a81c14SSteve Longerbeam  * should be identified and removed to speed register load time
41119a81c14SSteve Longerbeam  * over i2c.
41219a81c14SSteve Longerbeam  */
413fb98e29fSHugues Fruchet /* YUV422 UYVY VGA@30fps */
414e4359019SJacopo Mondi static const struct reg_value ov5640_init_setting[] = {
41519a81c14SSteve Longerbeam 	{0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0},
416576f5d4bSLad Prabhakar 	{0x3103, 0x03, 0, 0}, {0x3630, 0x36, 0, 0},
41719a81c14SSteve Longerbeam 	{0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0},
41819a81c14SSteve Longerbeam 	{0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0},
41919a81c14SSteve Longerbeam 	{0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0},
42019a81c14SSteve Longerbeam 	{0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, {0x3906, 0x10, 0, 0},
42119a81c14SSteve Longerbeam 	{0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, {0x3600, 0x08, 0, 0},
42219a81c14SSteve Longerbeam 	{0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, {0x3620, 0x52, 0, 0},
42319a81c14SSteve Longerbeam 	{0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, {0x3a13, 0x43, 0, 0},
42419a81c14SSteve Longerbeam 	{0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3635, 0x13, 0, 0},
42519a81c14SSteve Longerbeam 	{0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, {0x3622, 0x01, 0, 0},
42619a81c14SSteve Longerbeam 	{0x3c01, 0xa4, 0, 0}, {0x3c04, 0x28, 0, 0}, {0x3c05, 0x98, 0, 0},
42719a81c14SSteve Longerbeam 	{0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0},
42819a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
42919a81c14SSteve Longerbeam 	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
4303145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
43119a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
43219a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
43319a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
43419a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
43519a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
43619a81c14SSteve Longerbeam 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0},
43719a81c14SSteve Longerbeam 	{0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0},
438aa4bb8b8SJacopo Mondi 	{0x302e, 0x08, 0, 0}, {0x4300, 0x3f, 0, 0},
4392b5c18f9SChen-Yu Tsai 	{0x501f, 0x00, 0, 0}, {0x4407, 0x04, 0, 0},
44019a81c14SSteve Longerbeam 	{0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
441aa4bb8b8SJacopo Mondi 	{0x4837, 0x0a, 0, 0}, {0x3824, 0x02, 0, 0},
44219a81c14SSteve Longerbeam 	{0x5000, 0xa7, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0},
44319a81c14SSteve Longerbeam 	{0x5181, 0xf2, 0, 0}, {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0},
44419a81c14SSteve Longerbeam 	{0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0},
44519a81c14SSteve Longerbeam 	{0x5187, 0x09, 0, 0}, {0x5188, 0x09, 0, 0}, {0x5189, 0x88, 0, 0},
44619a81c14SSteve Longerbeam 	{0x518a, 0x54, 0, 0}, {0x518b, 0xee, 0, 0}, {0x518c, 0xb2, 0, 0},
44719a81c14SSteve Longerbeam 	{0x518d, 0x50, 0, 0}, {0x518e, 0x34, 0, 0}, {0x518f, 0x6b, 0, 0},
44819a81c14SSteve Longerbeam 	{0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0},
44919a81c14SSteve Longerbeam 	{0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0},
45019a81c14SSteve Longerbeam 	{0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0},
45119a81c14SSteve Longerbeam 	{0x5199, 0x6c, 0, 0}, {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0},
45219a81c14SSteve Longerbeam 	{0x519c, 0x09, 0, 0}, {0x519d, 0x2b, 0, 0}, {0x519e, 0x38, 0, 0},
45319a81c14SSteve Longerbeam 	{0x5381, 0x1e, 0, 0}, {0x5382, 0x5b, 0, 0}, {0x5383, 0x08, 0, 0},
45419a81c14SSteve Longerbeam 	{0x5384, 0x0a, 0, 0}, {0x5385, 0x7e, 0, 0}, {0x5386, 0x88, 0, 0},
45519a81c14SSteve Longerbeam 	{0x5387, 0x7c, 0, 0}, {0x5388, 0x6c, 0, 0}, {0x5389, 0x10, 0, 0},
45619a81c14SSteve Longerbeam 	{0x538a, 0x01, 0, 0}, {0x538b, 0x98, 0, 0}, {0x5300, 0x08, 0, 0},
45719a81c14SSteve Longerbeam 	{0x5301, 0x30, 0, 0}, {0x5302, 0x10, 0, 0}, {0x5303, 0x00, 0, 0},
45819a81c14SSteve Longerbeam 	{0x5304, 0x08, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x08, 0, 0},
45919a81c14SSteve Longerbeam 	{0x5307, 0x16, 0, 0}, {0x5309, 0x08, 0, 0}, {0x530a, 0x30, 0, 0},
46019a81c14SSteve Longerbeam 	{0x530b, 0x04, 0, 0}, {0x530c, 0x06, 0, 0}, {0x5480, 0x01, 0, 0},
46119a81c14SSteve Longerbeam 	{0x5481, 0x08, 0, 0}, {0x5482, 0x14, 0, 0}, {0x5483, 0x28, 0, 0},
46219a81c14SSteve Longerbeam 	{0x5484, 0x51, 0, 0}, {0x5485, 0x65, 0, 0}, {0x5486, 0x71, 0, 0},
46319a81c14SSteve Longerbeam 	{0x5487, 0x7d, 0, 0}, {0x5488, 0x87, 0, 0}, {0x5489, 0x91, 0, 0},
46419a81c14SSteve Longerbeam 	{0x548a, 0x9a, 0, 0}, {0x548b, 0xaa, 0, 0}, {0x548c, 0xb8, 0, 0},
46519a81c14SSteve Longerbeam 	{0x548d, 0xcd, 0, 0}, {0x548e, 0xdd, 0, 0}, {0x548f, 0xea, 0, 0},
46619a81c14SSteve Longerbeam 	{0x5490, 0x1d, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5583, 0x40, 0, 0},
46719a81c14SSteve Longerbeam 	{0x5584, 0x10, 0, 0}, {0x5589, 0x10, 0, 0}, {0x558a, 0x00, 0, 0},
46819a81c14SSteve Longerbeam 	{0x558b, 0xf8, 0, 0}, {0x5800, 0x23, 0, 0}, {0x5801, 0x14, 0, 0},
46919a81c14SSteve Longerbeam 	{0x5802, 0x0f, 0, 0}, {0x5803, 0x0f, 0, 0}, {0x5804, 0x12, 0, 0},
47019a81c14SSteve Longerbeam 	{0x5805, 0x26, 0, 0}, {0x5806, 0x0c, 0, 0}, {0x5807, 0x08, 0, 0},
47119a81c14SSteve Longerbeam 	{0x5808, 0x05, 0, 0}, {0x5809, 0x05, 0, 0}, {0x580a, 0x08, 0, 0},
47219a81c14SSteve Longerbeam 	{0x580b, 0x0d, 0, 0}, {0x580c, 0x08, 0, 0}, {0x580d, 0x03, 0, 0},
47319a81c14SSteve Longerbeam 	{0x580e, 0x00, 0, 0}, {0x580f, 0x00, 0, 0}, {0x5810, 0x03, 0, 0},
47419a81c14SSteve Longerbeam 	{0x5811, 0x09, 0, 0}, {0x5812, 0x07, 0, 0}, {0x5813, 0x03, 0, 0},
47519a81c14SSteve Longerbeam 	{0x5814, 0x00, 0, 0}, {0x5815, 0x01, 0, 0}, {0x5816, 0x03, 0, 0},
47619a81c14SSteve Longerbeam 	{0x5817, 0x08, 0, 0}, {0x5818, 0x0d, 0, 0}, {0x5819, 0x08, 0, 0},
47719a81c14SSteve Longerbeam 	{0x581a, 0x05, 0, 0}, {0x581b, 0x06, 0, 0}, {0x581c, 0x08, 0, 0},
47819a81c14SSteve Longerbeam 	{0x581d, 0x0e, 0, 0}, {0x581e, 0x29, 0, 0}, {0x581f, 0x17, 0, 0},
47919a81c14SSteve Longerbeam 	{0x5820, 0x11, 0, 0}, {0x5821, 0x11, 0, 0}, {0x5822, 0x15, 0, 0},
48019a81c14SSteve Longerbeam 	{0x5823, 0x28, 0, 0}, {0x5824, 0x46, 0, 0}, {0x5825, 0x26, 0, 0},
48119a81c14SSteve Longerbeam 	{0x5826, 0x08, 0, 0}, {0x5827, 0x26, 0, 0}, {0x5828, 0x64, 0, 0},
48219a81c14SSteve Longerbeam 	{0x5829, 0x26, 0, 0}, {0x582a, 0x24, 0, 0}, {0x582b, 0x22, 0, 0},
48319a81c14SSteve Longerbeam 	{0x582c, 0x24, 0, 0}, {0x582d, 0x24, 0, 0}, {0x582e, 0x06, 0, 0},
48419a81c14SSteve Longerbeam 	{0x582f, 0x22, 0, 0}, {0x5830, 0x40, 0, 0}, {0x5831, 0x42, 0, 0},
48519a81c14SSteve Longerbeam 	{0x5832, 0x24, 0, 0}, {0x5833, 0x26, 0, 0}, {0x5834, 0x24, 0, 0},
48619a81c14SSteve Longerbeam 	{0x5835, 0x22, 0, 0}, {0x5836, 0x22, 0, 0}, {0x5837, 0x26, 0, 0},
48719a81c14SSteve Longerbeam 	{0x5838, 0x44, 0, 0}, {0x5839, 0x24, 0, 0}, {0x583a, 0x26, 0, 0},
48819a81c14SSteve Longerbeam 	{0x583b, 0x28, 0, 0}, {0x583c, 0x42, 0, 0}, {0x583d, 0xce, 0, 0},
48919a81c14SSteve Longerbeam 	{0x5025, 0x00, 0, 0}, {0x3a0f, 0x30, 0, 0}, {0x3a10, 0x28, 0, 0},
49019a81c14SSteve Longerbeam 	{0x3a1b, 0x30, 0, 0}, {0x3a1e, 0x26, 0, 0}, {0x3a11, 0x60, 0, 0},
49119a81c14SSteve Longerbeam 	{0x3a1f, 0x14, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3c00, 0x04, 0, 300},
49219a81c14SSteve Longerbeam };
49319a81c14SSteve Longerbeam 
494db15c195SJacopo Mondi static const struct reg_value ov5640_setting_low_res[] = {
495c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
49619a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
497ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
4983145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
49919a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
50019a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
50119a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
50219a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
50319a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5042b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
505e15197bdSJacopo Mondi 	{0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0},
50619a81c14SSteve Longerbeam };
50719a81c14SSteve Longerbeam 
508086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_720P_1280_720[] = {
509c14d107eSMaxime Ripard 	{0x3c07, 0x07, 0, 0},
51019a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
511ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
5123145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
51319a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
51419a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0},
51519a81c14SSteve Longerbeam 	{0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0},
51619a81c14SSteve Longerbeam 	{0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0},
51719a81c14SSteve Longerbeam 	{0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0},
5182b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
51919a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
52019a81c14SSteve Longerbeam 	{0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0},
52119a81c14SSteve Longerbeam };
52219a81c14SSteve Longerbeam 
523086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_1080P_1920_1080[] = {
524c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
52519a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
526ce85705aSHugues Fruchet 	{0x3814, 0x11, 0, 0},
5273145efcdSJacopo Mondi 	{0x3815, 0x11, 0, 0},
52819a81c14SSteve Longerbeam 	{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
52919a81c14SSteve Longerbeam 	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
53019a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
53119a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
53219a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5332b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0},
53419a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
535c14d107eSMaxime Ripard 	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0},
536c14d107eSMaxime Ripard 	{0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0},
53719a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
538476dec01SMaxime Ripard 	{0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0},
53919a81c14SSteve Longerbeam 	{0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0},
54019a81c14SSteve Longerbeam 	{0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0},
54119a81c14SSteve Longerbeam 	{0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0},
5422b5c18f9SChen-Yu Tsai 	{0x3a15, 0x60, 0, 0}, {0x4407, 0x04, 0, 0},
54319a81c14SSteve Longerbeam 	{0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0},
54492b9096cSBenoit Parrot 	{0x4005, 0x1a, 0, 0},
54519a81c14SSteve Longerbeam };
54619a81c14SSteve Longerbeam 
547086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_QSXGA_2592_1944[] = {
548c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
54919a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
550ce85705aSHugues Fruchet 	{0x3814, 0x11, 0, 0},
5513145efcdSJacopo Mondi 	{0x3815, 0x11, 0, 0},
55219a81c14SSteve Longerbeam 	{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
55319a81c14SSteve Longerbeam 	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
55419a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
55519a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
55619a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5572b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0},
55819a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
55919a81c14SSteve Longerbeam 	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70},
56019a81c14SSteve Longerbeam };
56119a81c14SSteve Longerbeam 
5625113d5b3SJacopo Mondi static const struct ov5640_mode_info ov5640_mode_data[OV5640_NUM_MODES] = {
5638409d017SJacopo Mondi 	{
5648409d017SJacopo Mondi 		/* 160x120 */
5653145efcdSJacopo Mondi 		.id		= OV5640_MODE_QQVGA_160_120,
5663145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
5673145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
5685113d5b3SJacopo Mondi 		.width		= 160,
5695113d5b3SJacopo Mondi 		.height		= 120,
5705113d5b3SJacopo Mondi 		.dvp_timings = {
5713145efcdSJacopo Mondi 			.analog_crop = {
5723145efcdSJacopo Mondi 				.left	= 0,
5733145efcdSJacopo Mondi 				.top	= 4,
5743145efcdSJacopo Mondi 				.width	= 2624,
5753145efcdSJacopo Mondi 				.height	= 1944,
5763145efcdSJacopo Mondi 			},
5773145efcdSJacopo Mondi 			.crop = {
5783145efcdSJacopo Mondi 				.left	= 16,
5793145efcdSJacopo Mondi 				.top	= 6,
5803145efcdSJacopo Mondi 				.width	= 160,
5813145efcdSJacopo Mondi 				.height	= 120,
5823145efcdSJacopo Mondi 			},
5833145efcdSJacopo Mondi 			.htot		= 1896,
5843145efcdSJacopo Mondi 			.vblank_def	= 864,
5855113d5b3SJacopo Mondi 		},
5865113d5b3SJacopo Mondi 		.csi2_timings = {
5875113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
5885113d5b3SJacopo Mondi 			.analog_crop = {
5895113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
5905113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
5915113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
5925113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
5935113d5b3SJacopo Mondi 			},
5945113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
5955113d5b3SJacopo Mondi 			.crop = {
5965113d5b3SJacopo Mondi 				.left	= 2,
5975113d5b3SJacopo Mondi 				.top	= 4,
5985113d5b3SJacopo Mondi 				.width	= 160,
5995113d5b3SJacopo Mondi 				.height	= 120,
6005113d5b3SJacopo Mondi 			},
6015113d5b3SJacopo Mondi 			.htot		= 1896,
6025113d5b3SJacopo Mondi 			.vblank_def	= 864,
6035113d5b3SJacopo Mondi 		},
604db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
605db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
60619f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
60719f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
6088409d017SJacopo Mondi 	}, {
6098409d017SJacopo Mondi 		/* 176x144 */
6103145efcdSJacopo Mondi 		.id		= OV5640_MODE_QCIF_176_144,
6113145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
6123145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
6135113d5b3SJacopo Mondi 		.width		= 176,
6145113d5b3SJacopo Mondi 		.height		= 144,
6155113d5b3SJacopo Mondi 		.dvp_timings = {
6163145efcdSJacopo Mondi 			.analog_crop = {
6173145efcdSJacopo Mondi 				.left	= 0,
6183145efcdSJacopo Mondi 				.top	= 4,
6193145efcdSJacopo Mondi 				.width	= 2624,
6203145efcdSJacopo Mondi 				.height	= 1944,
6213145efcdSJacopo Mondi 			},
6223145efcdSJacopo Mondi 			.crop = {
6233145efcdSJacopo Mondi 				.left	= 16,
6243145efcdSJacopo Mondi 				.top	= 6,
6253145efcdSJacopo Mondi 				.width	= 176,
6263145efcdSJacopo Mondi 				.height	= 144,
6273145efcdSJacopo Mondi 			},
6283145efcdSJacopo Mondi 			.htot		= 1896,
6293145efcdSJacopo Mondi 			.vblank_def	= 840,
6305113d5b3SJacopo Mondi 		},
6315113d5b3SJacopo Mondi 		.csi2_timings = {
6325113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
6335113d5b3SJacopo Mondi 			.analog_crop = {
6345113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
6355113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
6365113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
6375113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
6385113d5b3SJacopo Mondi 			},
6395113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
6405113d5b3SJacopo Mondi 			.crop = {
6415113d5b3SJacopo Mondi 				.left	= 2,
6425113d5b3SJacopo Mondi 				.top	= 4,
6435113d5b3SJacopo Mondi 				.width	= 176,
6445113d5b3SJacopo Mondi 				.height	= 144,
6455113d5b3SJacopo Mondi 			},
6465113d5b3SJacopo Mondi 			.htot		= 1896,
6475113d5b3SJacopo Mondi 			.vblank_def	= 840,
6485113d5b3SJacopo Mondi 		},
649db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
650db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
65119f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
65219f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
6538409d017SJacopo Mondi 	}, {
6548409d017SJacopo Mondi 		/* 320x240 */
6553145efcdSJacopo Mondi 		.id		= OV5640_MODE_QVGA_320_240,
6563145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
6575113d5b3SJacopo Mondi 		.width		= 320,
6585113d5b3SJacopo Mondi 		.height		= 240,
6593145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
6605113d5b3SJacopo Mondi 		.dvp_timings = {
6613145efcdSJacopo Mondi 			.analog_crop = {
6623145efcdSJacopo Mondi 				.left	= 0,
6633145efcdSJacopo Mondi 				.top	= 4,
6643145efcdSJacopo Mondi 				.width	= 2624,
6653145efcdSJacopo Mondi 				.height	= 1944,
6663145efcdSJacopo Mondi 			},
6673145efcdSJacopo Mondi 			.crop = {
6683145efcdSJacopo Mondi 				.left	= 16,
6693145efcdSJacopo Mondi 				.top	= 6,
6703145efcdSJacopo Mondi 				.width	= 320,
6713145efcdSJacopo Mondi 				.height	= 240,
6723145efcdSJacopo Mondi 			},
6733145efcdSJacopo Mondi 			.htot		= 1896,
6743145efcdSJacopo Mondi 			.vblank_def	= 744,
6755113d5b3SJacopo Mondi 		},
6765113d5b3SJacopo Mondi 		.csi2_timings = {
6775113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
6785113d5b3SJacopo Mondi 			.analog_crop = {
6795113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
6805113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
6815113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
6825113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
6835113d5b3SJacopo Mondi 			},
6845113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
6855113d5b3SJacopo Mondi 			.crop = {
6865113d5b3SJacopo Mondi 				.left	= 2,
6875113d5b3SJacopo Mondi 				.top	= 4,
6885113d5b3SJacopo Mondi 				.width	= 320,
6895113d5b3SJacopo Mondi 				.height	= 240,
6905113d5b3SJacopo Mondi 			},
6915113d5b3SJacopo Mondi 			.htot		= 1896,
6925113d5b3SJacopo Mondi 			.vblank_def	= 744,
6935113d5b3SJacopo Mondi 		},
694db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
695db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
69619f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
69719f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
6988409d017SJacopo Mondi 	}, {
6998409d017SJacopo Mondi 		/* 640x480 */
7003145efcdSJacopo Mondi 		.id		= OV5640_MODE_VGA_640_480,
7013145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
7023145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
7035113d5b3SJacopo Mondi 		.width		= 640,
7045113d5b3SJacopo Mondi 		.height		= 480,
7055113d5b3SJacopo Mondi 		.dvp_timings = {
7063145efcdSJacopo Mondi 			.analog_crop = {
7073145efcdSJacopo Mondi 				.left	= 0,
7083145efcdSJacopo Mondi 				.top	= 4,
7093145efcdSJacopo Mondi 				.width	= 2624,
7103145efcdSJacopo Mondi 				.height	= 1944,
7113145efcdSJacopo Mondi 			},
7123145efcdSJacopo Mondi 			.crop = {
7133145efcdSJacopo Mondi 				.left	= 16,
7143145efcdSJacopo Mondi 				.top	= 6,
7153145efcdSJacopo Mondi 				.width	= 640,
7163145efcdSJacopo Mondi 				.height	= 480,
7173145efcdSJacopo Mondi 			},
7183145efcdSJacopo Mondi 			.htot		= 1896,
7193145efcdSJacopo Mondi 			.vblank_def	= 600,
7205113d5b3SJacopo Mondi 		},
7215113d5b3SJacopo Mondi 		.csi2_timings = {
7225113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
7235113d5b3SJacopo Mondi 			.analog_crop = {
7245113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
7255113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
7265113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
7275113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
7285113d5b3SJacopo Mondi 			},
7295113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
7305113d5b3SJacopo Mondi 			.crop = {
7315113d5b3SJacopo Mondi 				.left	= 2,
7325113d5b3SJacopo Mondi 				.top	= 4,
7335113d5b3SJacopo Mondi 				.width	= 640,
7345113d5b3SJacopo Mondi 				.height	= 480,
7355113d5b3SJacopo Mondi 			},
7365113d5b3SJacopo Mondi 			.htot		= 1896,
7375113d5b3SJacopo Mondi 			.vblank_def	= 600,
7385113d5b3SJacopo Mondi 		},
739db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
740db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
74119f2e3e6SHugues Fruchet 		.max_fps	= OV5640_60_FPS,
74219f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
7438409d017SJacopo Mondi 	}, {
7448409d017SJacopo Mondi 		/* 720x480 */
7453145efcdSJacopo Mondi 		.id		= OV5640_MODE_NTSC_720_480,
7463145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
7475113d5b3SJacopo Mondi 		.width		= 720,
7485113d5b3SJacopo Mondi 		.height		= 480,
7493145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
7505113d5b3SJacopo Mondi 		.dvp_timings = {
7513145efcdSJacopo Mondi 			.analog_crop = {
7523145efcdSJacopo Mondi 				.left	= 0,
7533145efcdSJacopo Mondi 				.top	= 4,
7543145efcdSJacopo Mondi 				.width	= 2624,
7553145efcdSJacopo Mondi 				.height	= 1944,
7563145efcdSJacopo Mondi 			},
7573145efcdSJacopo Mondi 			.crop = {
758e74ef55bSJacopo Mondi 				.left	= 56,
7593145efcdSJacopo Mondi 				.top	= 60,
7603145efcdSJacopo Mondi 				.width	= 720,
7613145efcdSJacopo Mondi 				.height	= 480,
7623145efcdSJacopo Mondi 			},
7633145efcdSJacopo Mondi 			.htot		= 1896,
7643145efcdSJacopo Mondi 			.vblank_def	= 504,
7655113d5b3SJacopo Mondi 		},
7665113d5b3SJacopo Mondi 		.csi2_timings = {
7675113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
7685113d5b3SJacopo Mondi 			.analog_crop = {
7695113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
7705113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
7715113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
7725113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
7735113d5b3SJacopo Mondi 			},
7745113d5b3SJacopo Mondi 			.crop = {
7755113d5b3SJacopo Mondi 				.left	= 56,
7765113d5b3SJacopo Mondi 				.top	= 60,
7775113d5b3SJacopo Mondi 				.width	= 720,
7785113d5b3SJacopo Mondi 				.height	= 480,
7795113d5b3SJacopo Mondi 			},
7805113d5b3SJacopo Mondi 			.htot		= 1896,
7815113d5b3SJacopo Mondi 			.vblank_def	= 504,
7825113d5b3SJacopo Mondi 		},
783db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
784db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
78519f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
78619f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
7878409d017SJacopo Mondi 	}, {
7888409d017SJacopo Mondi 		/* 720x576 */
7893145efcdSJacopo Mondi 		.id		= OV5640_MODE_PAL_720_576,
7903145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
7915113d5b3SJacopo Mondi 		.width		= 720,
7925113d5b3SJacopo Mondi 		.height		= 576,
7933145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
7945113d5b3SJacopo Mondi 		.dvp_timings = {
7953145efcdSJacopo Mondi 			.analog_crop = {
7963145efcdSJacopo Mondi 				.left	= 0,
7973145efcdSJacopo Mondi 				.top	= 4,
7983145efcdSJacopo Mondi 				.width	= 2624,
7993145efcdSJacopo Mondi 				.height	= 1944,
8003145efcdSJacopo Mondi 			},
8013145efcdSJacopo Mondi 			.crop = {
8023145efcdSJacopo Mondi 				.left	= 56,
8033145efcdSJacopo Mondi 				.top	= 6,
8043145efcdSJacopo Mondi 				.width	= 720,
8053145efcdSJacopo Mondi 				.height	= 576,
8063145efcdSJacopo Mondi 			},
8073145efcdSJacopo Mondi 			.htot		= 1896,
8083145efcdSJacopo Mondi 			.vblank_def	= 408,
8095113d5b3SJacopo Mondi 		},
8105113d5b3SJacopo Mondi 		.csi2_timings = {
8115113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
8125113d5b3SJacopo Mondi 			.analog_crop = {
8135113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
8145113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
8155113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
8165113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
8175113d5b3SJacopo Mondi 			},
8185113d5b3SJacopo Mondi 			.crop = {
8195113d5b3SJacopo Mondi 				.left	= 56,
8205113d5b3SJacopo Mondi 				.top	= 6,
8215113d5b3SJacopo Mondi 				.width	= 720,
8225113d5b3SJacopo Mondi 				.height	= 576,
8235113d5b3SJacopo Mondi 			},
8245113d5b3SJacopo Mondi 			.htot		= 1896,
8255113d5b3SJacopo Mondi 			.vblank_def	= 408,
8265113d5b3SJacopo Mondi 		},
827db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
828db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
82919f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
83019f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
8318409d017SJacopo Mondi 	}, {
8328409d017SJacopo Mondi 		/* 1024x768 */
8333145efcdSJacopo Mondi 		.id		= OV5640_MODE_XGA_1024_768,
8343145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
8353145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
8365113d5b3SJacopo Mondi 		.width		= 1024,
8375113d5b3SJacopo Mondi 		.height		= 768,
8385113d5b3SJacopo Mondi 		.dvp_timings = {
8393145efcdSJacopo Mondi 			.analog_crop = {
8403145efcdSJacopo Mondi 				.left	= 0,
8413145efcdSJacopo Mondi 				.top	= 4,
8423145efcdSJacopo Mondi 				.width	= 2624,
8433145efcdSJacopo Mondi 				.height	= 1944,
8443145efcdSJacopo Mondi 			},
8453145efcdSJacopo Mondi 			.crop = {
8463145efcdSJacopo Mondi 				.left	= 16,
8473145efcdSJacopo Mondi 				.top	= 6,
8483145efcdSJacopo Mondi 				.width	= 1024,
8493145efcdSJacopo Mondi 				.height	= 768,
8503145efcdSJacopo Mondi 			},
8513145efcdSJacopo Mondi 			.htot		= 1896,
8523145efcdSJacopo Mondi 			.vblank_def	= 312,
8535113d5b3SJacopo Mondi 		},
8545113d5b3SJacopo Mondi 		.csi2_timings = {
8555113d5b3SJacopo Mondi 			.analog_crop = {
8565113d5b3SJacopo Mondi 				.left	= 0,
8575113d5b3SJacopo Mondi 				.top	= 4,
8585113d5b3SJacopo Mondi 				.width	= OV5640_NATIVE_WIDTH,
8595113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
8605113d5b3SJacopo Mondi 			},
8615113d5b3SJacopo Mondi 			.crop = {
8625113d5b3SJacopo Mondi 				.left	= 16,
8635113d5b3SJacopo Mondi 				.top	= 6,
8645113d5b3SJacopo Mondi 				.width	= 1024,
8655113d5b3SJacopo Mondi 				.height	= 768,
8665113d5b3SJacopo Mondi 			},
8675113d5b3SJacopo Mondi 			.htot		= 1896,
8685113d5b3SJacopo Mondi 			.vblank_def	= 312,
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_30_FPS,
87319f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
8748409d017SJacopo Mondi 	}, {
8758409d017SJacopo Mondi 		/* 1280x720 */
8763145efcdSJacopo Mondi 		.id		= OV5640_MODE_720P_1280_720,
8773145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
8783145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_124M,
8795113d5b3SJacopo Mondi 		.width		= 1280,
8805113d5b3SJacopo Mondi 		.height		= 720,
8815113d5b3SJacopo Mondi 		.dvp_timings = {
8823145efcdSJacopo Mondi 			.analog_crop = {
8833145efcdSJacopo Mondi 				.left	= 0,
8843145efcdSJacopo Mondi 				.top	= 250,
8853145efcdSJacopo Mondi 				.width	= 2624,
8863145efcdSJacopo Mondi 				.height	= 1456,
8873145efcdSJacopo Mondi 			},
8883145efcdSJacopo Mondi 			.crop = {
8893145efcdSJacopo Mondi 				.left	= 16,
8903145efcdSJacopo Mondi 				.top	= 4,
8913145efcdSJacopo Mondi 				.width	= 1280,
8923145efcdSJacopo Mondi 				.height	= 720,
8933145efcdSJacopo Mondi 			},
8943145efcdSJacopo Mondi 			.htot		= 1892,
8953145efcdSJacopo Mondi 			.vblank_def	= 20,
8965113d5b3SJacopo Mondi 		},
8975113d5b3SJacopo Mondi 		.csi2_timings = {
8985113d5b3SJacopo Mondi 			.analog_crop = {
8995113d5b3SJacopo Mondi 				.left	= 0,
9005113d5b3SJacopo Mondi 				.top	= 250,
9015113d5b3SJacopo Mondi 				.width	= 2624,
9025113d5b3SJacopo Mondi 				.height	= 1456,
9035113d5b3SJacopo Mondi 			},
9045113d5b3SJacopo Mondi 			.crop = {
9055113d5b3SJacopo Mondi 				.left	= 16,
9065113d5b3SJacopo Mondi 				.top	= 4,
9075113d5b3SJacopo Mondi 				.width	= 1280,
9085113d5b3SJacopo Mondi 				.height	= 720,
9095113d5b3SJacopo Mondi 			},
9105113d5b3SJacopo Mondi 			.htot		= 1892,
9115113d5b3SJacopo Mondi 			.vblank_def	= 20,
9125113d5b3SJacopo Mondi 		},
9133145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_720P_1280_720,
9143145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_720P_1280_720),
91519f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
91619f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
9178409d017SJacopo Mondi 	}, {
9188409d017SJacopo Mondi 		/* 1920x1080 */
9193145efcdSJacopo Mondi 		.id		= OV5640_MODE_1080P_1920_1080,
9203145efcdSJacopo Mondi 		.dn_mode	= SCALING,
9213145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_148M,
9225113d5b3SJacopo Mondi 		.width		= 1920,
9235113d5b3SJacopo Mondi 		.height		= 1080,
9245113d5b3SJacopo Mondi 		.dvp_timings = {
9253145efcdSJacopo Mondi 			.analog_crop = {
9263145efcdSJacopo Mondi 				.left	= 336,
9273145efcdSJacopo Mondi 				.top	= 434,
9283145efcdSJacopo Mondi 				.width	= 1952,
9293145efcdSJacopo Mondi 				.height	= 1088,
9303145efcdSJacopo Mondi 			},
9313145efcdSJacopo Mondi 			.crop = {
9323145efcdSJacopo Mondi 				.left	= 16,
9333145efcdSJacopo Mondi 				.top	= 4,
9343145efcdSJacopo Mondi 				.width	= 1920,
9353145efcdSJacopo Mondi 				.height	= 1080,
9363145efcdSJacopo Mondi 			},
9373145efcdSJacopo Mondi 			.htot		= 2500,
9383145efcdSJacopo Mondi 			.vblank_def	= 40,
9395113d5b3SJacopo Mondi 		},
9405113d5b3SJacopo Mondi 		.csi2_timings = {
9415113d5b3SJacopo Mondi 			/* Crop the full valid pixel array in the center. */
9425113d5b3SJacopo Mondi 			.analog_crop = {
9435113d5b3SJacopo Mondi 				.left	= 336,
9445113d5b3SJacopo Mondi 				.top	= 434,
9455113d5b3SJacopo Mondi 				.width	= 1952,
9465113d5b3SJacopo Mondi 				.height	= 1088,
9475113d5b3SJacopo Mondi 			},
9485113d5b3SJacopo Mondi 			/* Maintain a larger processing margins. */
9495113d5b3SJacopo Mondi 			.crop = {
9505113d5b3SJacopo Mondi 				.left	= 16,
9515113d5b3SJacopo Mondi 				.top	= 4,
9525113d5b3SJacopo Mondi 				.width	= 1920,
9535113d5b3SJacopo Mondi 				.height	= 1080,
9545113d5b3SJacopo Mondi 			},
9555113d5b3SJacopo Mondi 			.htot		= 2500,
9565113d5b3SJacopo Mondi 			.vblank_def	= 40,
9575113d5b3SJacopo Mondi 		},
9583145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_1080P_1920_1080,
9593145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_1080P_1920_1080),
96019f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
96119f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
9628409d017SJacopo Mondi 	}, {
9638409d017SJacopo Mondi 		/* 2592x1944 */
9643145efcdSJacopo Mondi 		.id		= OV5640_MODE_QSXGA_2592_1944,
9653145efcdSJacopo Mondi 		.dn_mode	= SCALING,
9663145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_168M,
9675113d5b3SJacopo Mondi 		.width		= OV5640_PIXEL_ARRAY_WIDTH,
9685113d5b3SJacopo Mondi 		.height		= OV5640_PIXEL_ARRAY_HEIGHT,
9695113d5b3SJacopo Mondi 		.dvp_timings = {
9703145efcdSJacopo Mondi 			.analog_crop = {
9713145efcdSJacopo Mondi 				.left	= 0,
9723145efcdSJacopo Mondi 				.top	= 0,
9733145efcdSJacopo Mondi 				.width	= 2624,
9743145efcdSJacopo Mondi 				.height	= 1952,
9753145efcdSJacopo Mondi 			},
9763145efcdSJacopo Mondi 			.crop = {
9773145efcdSJacopo Mondi 				.left	= 16,
9783145efcdSJacopo Mondi 				.top	= 4,
9793145efcdSJacopo Mondi 				.width	= 2592,
9803145efcdSJacopo Mondi 				.height	= 1944,
9813145efcdSJacopo Mondi 			},
9823145efcdSJacopo Mondi 			.htot		= 2844,
9833145efcdSJacopo Mondi 			.vblank_def	= 24,
9845113d5b3SJacopo Mondi 		},
9855113d5b3SJacopo Mondi 		.csi2_timings = {
9865113d5b3SJacopo Mondi 			/* Give more processing margin to full resolution. */
9875113d5b3SJacopo Mondi 			.analog_crop = {
9885113d5b3SJacopo Mondi 				.left	= 0,
9895113d5b3SJacopo Mondi 				.top	= 0,
9905113d5b3SJacopo Mondi 				.width	= OV5640_NATIVE_WIDTH,
9915113d5b3SJacopo Mondi 				.height	= 1952,
9925113d5b3SJacopo Mondi 			},
9935113d5b3SJacopo Mondi 			.crop = {
9945113d5b3SJacopo Mondi 				.left	= 16,
9955113d5b3SJacopo Mondi 				.top	= 4,
9965113d5b3SJacopo Mondi 				.width	= 2592,
9975113d5b3SJacopo Mondi 				.height	= 1944,
9985113d5b3SJacopo Mondi 			},
9995113d5b3SJacopo Mondi 			.htot		= 2844,
10005113d5b3SJacopo Mondi 			.vblank_def	= 24,
10015113d5b3SJacopo Mondi 		},
10023145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_QSXGA_2592_1944,
10033145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_QSXGA_2592_1944),
100419f2e3e6SHugues Fruchet 		.max_fps	= OV5640_15_FPS,
100519f2e3e6SHugues Fruchet 		.def_fps	= OV5640_15_FPS
10068409d017SJacopo Mondi 	},
100719a81c14SSteve Longerbeam };
100819a81c14SSteve Longerbeam 
10092de6bb97SJacopo Mondi static const struct ov5640_timings *
10102de6bb97SJacopo Mondi ov5640_timings(const struct ov5640_dev *sensor,
10112de6bb97SJacopo Mondi 	       const struct ov5640_mode_info *mode)
10122de6bb97SJacopo Mondi {
10132de6bb97SJacopo Mondi 	if (ov5640_is_csi2(sensor))
10142de6bb97SJacopo Mondi 		return &mode->csi2_timings;
10152de6bb97SJacopo Mondi 
10162de6bb97SJacopo Mondi 	return &mode->dvp_timings;
10172de6bb97SJacopo Mondi }
10182de6bb97SJacopo Mondi 
101919a81c14SSteve Longerbeam static int ov5640_init_slave_id(struct ov5640_dev *sensor)
102019a81c14SSteve Longerbeam {
102119a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
102219a81c14SSteve Longerbeam 	struct i2c_msg msg;
102319a81c14SSteve Longerbeam 	u8 buf[3];
102419a81c14SSteve Longerbeam 	int ret;
102519a81c14SSteve Longerbeam 
102619a81c14SSteve Longerbeam 	if (client->addr == OV5640_DEFAULT_SLAVE_ID)
102719a81c14SSteve Longerbeam 		return 0;
102819a81c14SSteve Longerbeam 
102919a81c14SSteve Longerbeam 	buf[0] = OV5640_REG_SLAVE_ID >> 8;
103019a81c14SSteve Longerbeam 	buf[1] = OV5640_REG_SLAVE_ID & 0xff;
103119a81c14SSteve Longerbeam 	buf[2] = client->addr << 1;
103219a81c14SSteve Longerbeam 
103319a81c14SSteve Longerbeam 	msg.addr = OV5640_DEFAULT_SLAVE_ID;
103419a81c14SSteve Longerbeam 	msg.flags = 0;
103519a81c14SSteve Longerbeam 	msg.buf = buf;
103619a81c14SSteve Longerbeam 	msg.len = sizeof(buf);
103719a81c14SSteve Longerbeam 
103819a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, &msg, 1);
103919a81c14SSteve Longerbeam 	if (ret < 0) {
104019a81c14SSteve Longerbeam 		dev_err(&client->dev, "%s: failed with %d\n", __func__, ret);
104119a81c14SSteve Longerbeam 		return ret;
104219a81c14SSteve Longerbeam 	}
104319a81c14SSteve Longerbeam 
104419a81c14SSteve Longerbeam 	return 0;
104519a81c14SSteve Longerbeam }
104619a81c14SSteve Longerbeam 
104719a81c14SSteve Longerbeam static int ov5640_write_reg(struct ov5640_dev *sensor, u16 reg, u8 val)
104819a81c14SSteve Longerbeam {
104919a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
105019a81c14SSteve Longerbeam 	struct i2c_msg msg;
105119a81c14SSteve Longerbeam 	u8 buf[3];
105219a81c14SSteve Longerbeam 	int ret;
105319a81c14SSteve Longerbeam 
105419a81c14SSteve Longerbeam 	buf[0] = reg >> 8;
105519a81c14SSteve Longerbeam 	buf[1] = reg & 0xff;
105619a81c14SSteve Longerbeam 	buf[2] = val;
105719a81c14SSteve Longerbeam 
105819a81c14SSteve Longerbeam 	msg.addr = client->addr;
105919a81c14SSteve Longerbeam 	msg.flags = client->flags;
106019a81c14SSteve Longerbeam 	msg.buf = buf;
106119a81c14SSteve Longerbeam 	msg.len = sizeof(buf);
106219a81c14SSteve Longerbeam 
106319a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, &msg, 1);
106419a81c14SSteve Longerbeam 	if (ret < 0) {
10653924c623SHugues Fruchet 		dev_err(&client->dev, "%s: error: reg=%x, val=%x\n",
106619a81c14SSteve Longerbeam 			__func__, reg, val);
106719a81c14SSteve Longerbeam 		return ret;
106819a81c14SSteve Longerbeam 	}
106919a81c14SSteve Longerbeam 
107019a81c14SSteve Longerbeam 	return 0;
107119a81c14SSteve Longerbeam }
107219a81c14SSteve Longerbeam 
107319a81c14SSteve Longerbeam static int ov5640_read_reg(struct ov5640_dev *sensor, u16 reg, u8 *val)
107419a81c14SSteve Longerbeam {
107519a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
107619a81c14SSteve Longerbeam 	struct i2c_msg msg[2];
107719a81c14SSteve Longerbeam 	u8 buf[2];
107819a81c14SSteve Longerbeam 	int ret;
107919a81c14SSteve Longerbeam 
108019a81c14SSteve Longerbeam 	buf[0] = reg >> 8;
108119a81c14SSteve Longerbeam 	buf[1] = reg & 0xff;
108219a81c14SSteve Longerbeam 
108319a81c14SSteve Longerbeam 	msg[0].addr = client->addr;
108419a81c14SSteve Longerbeam 	msg[0].flags = client->flags;
108519a81c14SSteve Longerbeam 	msg[0].buf = buf;
108619a81c14SSteve Longerbeam 	msg[0].len = sizeof(buf);
108719a81c14SSteve Longerbeam 
108819a81c14SSteve Longerbeam 	msg[1].addr = client->addr;
108919a81c14SSteve Longerbeam 	msg[1].flags = client->flags | I2C_M_RD;
109019a81c14SSteve Longerbeam 	msg[1].buf = buf;
109119a81c14SSteve Longerbeam 	msg[1].len = 1;
109219a81c14SSteve Longerbeam 
109319a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, msg, 2);
10943924c623SHugues Fruchet 	if (ret < 0) {
10953924c623SHugues Fruchet 		dev_err(&client->dev, "%s: error: reg=%x\n",
10963924c623SHugues Fruchet 			__func__, reg);
109719a81c14SSteve Longerbeam 		return ret;
10983924c623SHugues Fruchet 	}
109919a81c14SSteve Longerbeam 
110019a81c14SSteve Longerbeam 	*val = buf[0];
110119a81c14SSteve Longerbeam 	return 0;
110219a81c14SSteve Longerbeam }
110319a81c14SSteve Longerbeam 
110419a81c14SSteve Longerbeam static int ov5640_read_reg16(struct ov5640_dev *sensor, u16 reg, u16 *val)
110519a81c14SSteve Longerbeam {
110619a81c14SSteve Longerbeam 	u8 hi, lo;
110719a81c14SSteve Longerbeam 	int ret;
110819a81c14SSteve Longerbeam 
110919a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg, &hi);
111019a81c14SSteve Longerbeam 	if (ret)
111119a81c14SSteve Longerbeam 		return ret;
111219a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg + 1, &lo);
111319a81c14SSteve Longerbeam 	if (ret)
111419a81c14SSteve Longerbeam 		return ret;
111519a81c14SSteve Longerbeam 
111619a81c14SSteve Longerbeam 	*val = ((u16)hi << 8) | (u16)lo;
111719a81c14SSteve Longerbeam 	return 0;
111819a81c14SSteve Longerbeam }
111919a81c14SSteve Longerbeam 
112019a81c14SSteve Longerbeam static int ov5640_write_reg16(struct ov5640_dev *sensor, u16 reg, u16 val)
112119a81c14SSteve Longerbeam {
112219a81c14SSteve Longerbeam 	int ret;
112319a81c14SSteve Longerbeam 
112419a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, reg, val >> 8);
112519a81c14SSteve Longerbeam 	if (ret)
112619a81c14SSteve Longerbeam 		return ret;
112719a81c14SSteve Longerbeam 
112819a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, reg + 1, val & 0xff);
112919a81c14SSteve Longerbeam }
113019a81c14SSteve Longerbeam 
113119a81c14SSteve Longerbeam static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg,
113219a81c14SSteve Longerbeam 			  u8 mask, u8 val)
113319a81c14SSteve Longerbeam {
113419a81c14SSteve Longerbeam 	u8 readval;
113519a81c14SSteve Longerbeam 	int ret;
113619a81c14SSteve Longerbeam 
113719a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg, &readval);
113819a81c14SSteve Longerbeam 	if (ret)
113919a81c14SSteve Longerbeam 		return ret;
114019a81c14SSteve Longerbeam 
114119a81c14SSteve Longerbeam 	readval &= ~mask;
114219a81c14SSteve Longerbeam 	val &= mask;
114319a81c14SSteve Longerbeam 	val |= readval;
114419a81c14SSteve Longerbeam 
114519a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, reg, val);
114619a81c14SSteve Longerbeam }
114719a81c14SSteve Longerbeam 
1148aa288248SMaxime Ripard /*
1149aa288248SMaxime Ripard  * After trying the various combinations, reading various
1150f8a7647dSMauro Carvalho Chehab  * documentations spread around the net, and from the various
1151aa288248SMaxime Ripard  * feedback, the clock tree is probably as follows:
1152aa288248SMaxime Ripard  *
1153aa288248SMaxime Ripard  *   +--------------+
1154aa288248SMaxime Ripard  *   |  Ext. Clock  |
1155aa288248SMaxime Ripard  *   +-+------------+
1156aa288248SMaxime Ripard  *     |  +----------+
1157aa288248SMaxime Ripard  *     +->|   PLL1   | - reg 0x3036, for the multiplier
1158aa288248SMaxime Ripard  *        +-+--------+ - reg 0x3037, bits 0-3 for the pre-divider
1159aa288248SMaxime Ripard  *          |  +--------------+
1160aa288248SMaxime Ripard  *          +->| System Clock |  - reg 0x3035, bits 4-7
1161aa288248SMaxime Ripard  *             +-+------------+
1162aa288248SMaxime Ripard  *               |  +--------------+
1163aa288248SMaxime Ripard  *               +->| MIPI Divider | - reg 0x3035, bits 0-3
1164aa288248SMaxime Ripard  *               |  +-+------------+
1165aa288248SMaxime Ripard  *               |    +----------------> MIPI SCLK
1166aa288248SMaxime Ripard  *               |    +  +-----+
1167aa288248SMaxime Ripard  *               |    +->| / 2 |-------> MIPI BIT CLK
1168aa288248SMaxime Ripard  *               |       +-----+
1169aa288248SMaxime Ripard  *               |  +--------------+
1170aa288248SMaxime Ripard  *               +->| PLL Root Div | - reg 0x3037, bit 4
1171aa288248SMaxime Ripard  *                  +-+------------+
1172aa288248SMaxime Ripard  *                    |  +---------+
11734c85f628SPaul Kocialkowski  *                    +->| Bit Div | - reg 0x3034, bits 0-3
1174aa288248SMaxime Ripard  *                       +-+-------+
1175aa288248SMaxime Ripard  *                         |  +-------------+
1176aa288248SMaxime Ripard  *                         +->| SCLK Div    | - reg 0x3108, bits 0-1
1177aa288248SMaxime Ripard  *                         |  +-+-----------+
1178aa288248SMaxime Ripard  *                         |    +---------------> SCLK
1179aa288248SMaxime Ripard  *                         |  +-------------+
1180aa288248SMaxime Ripard  *                         +->| SCLK 2X Div | - reg 0x3108, bits 2-3
1181aa288248SMaxime Ripard  *                         |  +-+-----------+
1182aa288248SMaxime Ripard  *                         |    +---------------> SCLK 2X
1183aa288248SMaxime Ripard  *                         |  +-------------+
1184aa288248SMaxime Ripard  *                         +->| PCLK Div    | - reg 0x3108, bits 4-5
1185aa288248SMaxime Ripard  *                            ++------------+
1186aa288248SMaxime Ripard  *                             +  +-----------+
1187aa288248SMaxime Ripard  *                             +->|   P_DIV   | - reg 0x3035, bits 0-3
1188aa288248SMaxime Ripard  *                                +-----+-----+
1189aa288248SMaxime Ripard  *                                       +------------> PCLK
1190aa288248SMaxime Ripard  *
11916c957ed7SJacopo Mondi  * There seems to be also constraints:
1192aa288248SMaxime Ripard  *  - the PLL pre-divider output rate should be in the 4-27MHz range
1193aa288248SMaxime Ripard  *  - the PLL multiplier output rate should be in the 500-1000MHz range
1194aa288248SMaxime Ripard  *  - PCLK >= SCLK * 2 in YUV, >= SCLK in Raw or JPEG
1195aa288248SMaxime Ripard  */
1196aa288248SMaxime Ripard 
1197aa288248SMaxime Ripard /*
1198aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1199aa288248SMaxime Ripard  * set to 3 in the vendor kernels.
1200aa288248SMaxime Ripard  */
1201aa288248SMaxime Ripard #define OV5640_PLL_PREDIV	3
1202aa288248SMaxime Ripard 
1203aa288248SMaxime Ripard #define OV5640_PLL_MULT_MIN	4
1204aa288248SMaxime Ripard #define OV5640_PLL_MULT_MAX	252
1205aa288248SMaxime Ripard 
1206aa288248SMaxime Ripard /*
1207aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 16, but the value is
1208aa288248SMaxime Ripard  * always set to either 1 or 2 in the vendor kernels.
1209aa288248SMaxime Ripard  */
1210aa288248SMaxime Ripard #define OV5640_SYSDIV_MIN	1
1211aa288248SMaxime Ripard #define OV5640_SYSDIV_MAX	16
1212aa288248SMaxime Ripard 
1213aa288248SMaxime Ripard /*
1214aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 2, but the value is always
1215aa288248SMaxime Ripard  * set to 2 in the vendor kernels.
1216aa288248SMaxime Ripard  */
1217aa288248SMaxime Ripard #define OV5640_PLL_ROOT_DIV			2
1218aa288248SMaxime Ripard #define OV5640_PLL_CTRL3_PLL_ROOT_DIV_2		BIT(4)
1219aa288248SMaxime Ripard 
1220aa288248SMaxime Ripard /*
1221aa288248SMaxime Ripard  * We only supports 8-bit formats at the moment
1222aa288248SMaxime Ripard  */
1223aa288248SMaxime Ripard #define OV5640_BIT_DIV				2
1224aa288248SMaxime Ripard #define OV5640_PLL_CTRL0_MIPI_MODE_8BIT		0x08
1225aa288248SMaxime Ripard 
1226aa288248SMaxime Ripard /*
1227aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1228aa288248SMaxime Ripard  * set to 2 in the vendor kernels.
1229aa288248SMaxime Ripard  */
1230aa288248SMaxime Ripard #define OV5640_SCLK_ROOT_DIV	2
1231aa288248SMaxime Ripard 
1232aa288248SMaxime Ripard /*
1233aa288248SMaxime Ripard  * This is hardcoded so that the consistency is maintained between SCLK and
1234aa288248SMaxime Ripard  * SCLK 2x.
1235aa288248SMaxime Ripard  */
1236aa288248SMaxime Ripard #define OV5640_SCLK2X_ROOT_DIV (OV5640_SCLK_ROOT_DIV / 2)
1237aa288248SMaxime Ripard 
1238aa288248SMaxime Ripard /*
1239aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1240aa288248SMaxime Ripard  * set to 1 in the vendor kernels.
1241aa288248SMaxime Ripard  */
1242aa288248SMaxime Ripard #define OV5640_PCLK_ROOT_DIV			1
1243aa288248SMaxime Ripard #define OV5640_PLL_SYS_ROOT_DIVIDER_BYPASS	0x00
1244aa288248SMaxime Ripard 
1245aa288248SMaxime Ripard static unsigned long ov5640_compute_sys_clk(struct ov5640_dev *sensor,
1246aa288248SMaxime Ripard 					    u8 pll_prediv, u8 pll_mult,
1247aa288248SMaxime Ripard 					    u8 sysdiv)
1248aa288248SMaxime Ripard {
1249aa288248SMaxime Ripard 	unsigned long sysclk = sensor->xclk_freq / pll_prediv * pll_mult;
1250aa288248SMaxime Ripard 
1251aa288248SMaxime Ripard 	/* PLL1 output cannot exceed 1GHz. */
1252aa288248SMaxime Ripard 	if (sysclk / 1000000 > 1000)
1253aa288248SMaxime Ripard 		return 0;
1254aa288248SMaxime Ripard 
1255aa288248SMaxime Ripard 	return sysclk / sysdiv;
1256aa288248SMaxime Ripard }
1257aa288248SMaxime Ripard 
1258aa288248SMaxime Ripard static unsigned long ov5640_calc_sys_clk(struct ov5640_dev *sensor,
1259aa288248SMaxime Ripard 					 unsigned long rate,
1260aa288248SMaxime Ripard 					 u8 *pll_prediv, u8 *pll_mult,
1261aa288248SMaxime Ripard 					 u8 *sysdiv)
1262aa288248SMaxime Ripard {
1263aa288248SMaxime Ripard 	unsigned long best = ~0;
1264aa288248SMaxime Ripard 	u8 best_sysdiv = 1, best_mult = 1;
1265aa288248SMaxime Ripard 	u8 _sysdiv, _pll_mult;
1266aa288248SMaxime Ripard 
1267aa288248SMaxime Ripard 	for (_sysdiv = OV5640_SYSDIV_MIN;
1268aa288248SMaxime Ripard 	     _sysdiv <= OV5640_SYSDIV_MAX;
1269aa288248SMaxime Ripard 	     _sysdiv++) {
1270aa288248SMaxime Ripard 		for (_pll_mult = OV5640_PLL_MULT_MIN;
1271aa288248SMaxime Ripard 		     _pll_mult <= OV5640_PLL_MULT_MAX;
1272aa288248SMaxime Ripard 		     _pll_mult++) {
1273aa288248SMaxime Ripard 			unsigned long _rate;
1274aa288248SMaxime Ripard 
1275aa288248SMaxime Ripard 			/*
1276aa288248SMaxime Ripard 			 * The PLL multiplier cannot be odd if above
1277aa288248SMaxime Ripard 			 * 127.
1278aa288248SMaxime Ripard 			 */
1279aa288248SMaxime Ripard 			if (_pll_mult > 127 && (_pll_mult % 2))
1280aa288248SMaxime Ripard 				continue;
1281aa288248SMaxime Ripard 
1282aa288248SMaxime Ripard 			_rate = ov5640_compute_sys_clk(sensor,
1283aa288248SMaxime Ripard 						       OV5640_PLL_PREDIV,
1284aa288248SMaxime Ripard 						       _pll_mult, _sysdiv);
1285aa288248SMaxime Ripard 
1286aa288248SMaxime Ripard 			/*
1287aa288248SMaxime Ripard 			 * We have reached the maximum allowed PLL1 output,
1288aa288248SMaxime Ripard 			 * increase sysdiv.
1289aa288248SMaxime Ripard 			 */
12902e3df204SAdam Ford 			if (!_rate)
1291aa288248SMaxime Ripard 				break;
1292aa288248SMaxime Ripard 
1293aa288248SMaxime Ripard 			/*
1294aa288248SMaxime Ripard 			 * Prefer rates above the expected clock rate than
1295aa288248SMaxime Ripard 			 * below, even if that means being less precise.
1296aa288248SMaxime Ripard 			 */
1297aa288248SMaxime Ripard 			if (_rate < rate)
1298aa288248SMaxime Ripard 				continue;
1299aa288248SMaxime Ripard 
1300aa288248SMaxime Ripard 			if (abs(rate - _rate) < abs(rate - best)) {
1301aa288248SMaxime Ripard 				best = _rate;
1302aa288248SMaxime Ripard 				best_sysdiv = _sysdiv;
1303aa288248SMaxime Ripard 				best_mult = _pll_mult;
1304aa288248SMaxime Ripard 			}
1305aa288248SMaxime Ripard 
1306aa288248SMaxime Ripard 			if (_rate == rate)
1307aa288248SMaxime Ripard 				goto out;
1308aa288248SMaxime Ripard 		}
1309aa288248SMaxime Ripard 	}
1310aa288248SMaxime Ripard 
1311aa288248SMaxime Ripard out:
1312aa288248SMaxime Ripard 	*sysdiv = best_sysdiv;
1313aa288248SMaxime Ripard 	*pll_prediv = OV5640_PLL_PREDIV;
1314aa288248SMaxime Ripard 	*pll_mult = best_mult;
1315aa288248SMaxime Ripard 
1316aa288248SMaxime Ripard 	return best;
1317aa288248SMaxime Ripard }
1318aa288248SMaxime Ripard 
1319aa288248SMaxime Ripard /*
1320aa288248SMaxime Ripard  * ov5640_set_mipi_pclk() - Calculate the clock tree configuration values
1321aa288248SMaxime Ripard  *			    for the MIPI CSI-2 output.
1322aa288248SMaxime Ripard  */
13236c957ed7SJacopo Mondi static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor)
1324aa288248SMaxime Ripard {
13256c957ed7SJacopo Mondi 	u8 bit_div, mipi_div, pclk_div, sclk_div, sclk2x_div, root_div;
1326aa288248SMaxime Ripard 	u8 prediv, mult, sysdiv;
13276c957ed7SJacopo Mondi 	unsigned long link_freq;
13286c957ed7SJacopo Mondi 	unsigned long sysclk;
13296c957ed7SJacopo Mondi 	u8 pclk_period;
13306c957ed7SJacopo Mondi 	u32 sample_rate;
13316c957ed7SJacopo Mondi 	u32 num_lanes;
1332aa288248SMaxime Ripard 	int ret;
1333aa288248SMaxime Ripard 
13346c957ed7SJacopo Mondi 	/* Use the link freq computed at ov5640_update_pixel_rate() time. */
13356c957ed7SJacopo Mondi 	link_freq = sensor->current_link_freq;
13366c957ed7SJacopo Mondi 
1337aa288248SMaxime Ripard 	/*
13386c957ed7SJacopo Mondi 	 * - mipi_div - Additional divider for the MIPI lane clock.
13396c957ed7SJacopo Mondi 	 *
13406c957ed7SJacopo Mondi 	 * Higher link frequencies would make sysclk > 1GHz.
13416c957ed7SJacopo Mondi 	 * Keep the sysclk low and do not divide in the MIPI domain.
1342aa288248SMaxime Ripard 	 */
13436c957ed7SJacopo Mondi 	if (link_freq > OV5640_LINK_RATE_MAX)
13446c957ed7SJacopo Mondi 		mipi_div = 1;
1345aa288248SMaxime Ripard 	else
13466c957ed7SJacopo Mondi 		mipi_div = 2;
1347aa288248SMaxime Ripard 
13486c957ed7SJacopo Mondi 	sysclk = link_freq * mipi_div;
13496c957ed7SJacopo Mondi 	ov5640_calc_sys_clk(sensor, sysclk, &prediv, &mult, &sysdiv);
1350aa288248SMaxime Ripard 
13516c957ed7SJacopo Mondi 	/*
13526c957ed7SJacopo Mondi 	 * Adjust PLL parameters to maintain the MIPI_SCLK-to-PCLK ratio.
13536c957ed7SJacopo Mondi 	 *
13546c957ed7SJacopo Mondi 	 * - root_div = 2 (fixed)
13556c957ed7SJacopo Mondi 	 * - bit_div : MIPI 8-bit = 2; MIPI 10-bit = 2.5
13566c957ed7SJacopo Mondi 	 * - pclk_div = 1 (fixed)
13576c957ed7SJacopo Mondi 	 * - p_div  = (2 lanes ? mipi_div : 2 * mipi_div)
13586c957ed7SJacopo Mondi 	 *
13596c957ed7SJacopo Mondi 	 * This results in the following MIPI_SCLK depending on the number
13606c957ed7SJacopo Mondi 	 * of lanes:
13616c957ed7SJacopo Mondi 	 *
13626c957ed7SJacopo Mondi 	 * - 2 lanes: MIPI_SCLK = (4 or 5) * PCLK
13636c957ed7SJacopo Mondi 	 * - 1 lanes: MIPI_SCLK = (8 or 10) * PCLK
13646c957ed7SJacopo Mondi 	 */
13656c957ed7SJacopo Mondi 	root_div = OV5640_PLL_CTRL3_PLL_ROOT_DIV_2;
13666c957ed7SJacopo Mondi 	bit_div =  OV5640_PLL_CTRL0_MIPI_MODE_8BIT;
13676c957ed7SJacopo Mondi 	pclk_div = ilog2(OV5640_PCLK_ROOT_DIV);
1368aa288248SMaxime Ripard 
13696c957ed7SJacopo Mondi 	/*
13706c957ed7SJacopo Mondi 	 * Scaler clock:
13716c957ed7SJacopo Mondi 	 * - YUV: PCLK >= 2 * SCLK
13726c957ed7SJacopo Mondi 	 * - RAW or JPEG: PCLK >= SCLK
13736c957ed7SJacopo Mondi 	 * - sclk2x_div = sclk_div / 2
13746c957ed7SJacopo Mondi 	 */
13756c957ed7SJacopo Mondi 	sclk_div = ilog2(OV5640_SCLK_ROOT_DIV);
13766c957ed7SJacopo Mondi 	sclk2x_div = ilog2(OV5640_SCLK2X_ROOT_DIV);
13776c957ed7SJacopo Mondi 
13786c957ed7SJacopo Mondi 	/*
13796c957ed7SJacopo Mondi 	 * Set the pixel clock period expressed in ns with 1-bit decimal
13806c957ed7SJacopo Mondi 	 * (0x01=0.5ns).
13816c957ed7SJacopo Mondi 	 *
13826c957ed7SJacopo Mondi 	 * The register is very briefly documented. In the OV5645 datasheet it
13836c957ed7SJacopo Mondi 	 * is described as (2 * pclk period), and from testing it seems the
13846c957ed7SJacopo Mondi 	 * actual definition is 2 * 8-bit sample period.
13856c957ed7SJacopo Mondi 	 *
13866c957ed7SJacopo Mondi 	 * 2 * sample_period = (mipi_clk * 2 * num_lanes / bpp) * (bpp / 8) / 2
13876c957ed7SJacopo Mondi 	 */
13886c957ed7SJacopo Mondi 	num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes;
13896c957ed7SJacopo Mondi 	sample_rate = (link_freq * mipi_div * num_lanes * 2) / 16;
13906c957ed7SJacopo Mondi 	pclk_period = 2000000000UL / sample_rate;
13916c957ed7SJacopo Mondi 
13926c957ed7SJacopo Mondi 	/* Program the clock tree registers. */
13936c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0, 0x0f, bit_div);
13946c957ed7SJacopo Mondi 	if (ret)
13956c957ed7SJacopo Mondi 		return ret;
13966c957ed7SJacopo Mondi 
13976c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, 0xff,
13986c957ed7SJacopo Mondi 			     (sysdiv << 4) | mipi_div);
1399aa288248SMaxime Ripard 	if (ret)
1400aa288248SMaxime Ripard 		return ret;
1401aa288248SMaxime Ripard 
1402aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2, 0xff, mult);
1403aa288248SMaxime Ripard 	if (ret)
1404aa288248SMaxime Ripard 		return ret;
1405aa288248SMaxime Ripard 
14066c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3, 0x1f,
14076c957ed7SJacopo Mondi 			     root_div | prediv);
1408aa288248SMaxime Ripard 	if (ret)
1409aa288248SMaxime Ripard 		return ret;
1410aa288248SMaxime Ripard 
14116c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
14126c957ed7SJacopo Mondi 			     (pclk_div << 4) | (sclk2x_div << 2) | sclk_div);
14136c957ed7SJacopo Mondi 	if (ret)
14146c957ed7SJacopo Mondi 		return ret;
14156c957ed7SJacopo Mondi 
14166c957ed7SJacopo Mondi 	return ov5640_write_reg(sensor, OV5640_REG_PCLK_PERIOD, pclk_period);
14176c957ed7SJacopo Mondi }
14186c957ed7SJacopo Mondi 
14196c957ed7SJacopo Mondi static u32 ov5640_calc_pixel_rate(struct ov5640_dev *sensor)
14206c957ed7SJacopo Mondi {
14213145efcdSJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
14225113d5b3SJacopo Mondi 	const struct ov5640_timings *timings = &mode->dvp_timings;
14236c957ed7SJacopo Mondi 	u32 rate;
14246c957ed7SJacopo Mondi 
14255113d5b3SJacopo Mondi 	rate = timings->htot * (timings->crop.height + timings->vblank_def);
14266c957ed7SJacopo Mondi 	rate *= ov5640_framerates[sensor->current_fr];
14276c957ed7SJacopo Mondi 
14286c957ed7SJacopo Mondi 	return rate;
1429aa288248SMaxime Ripard }
1430aa288248SMaxime Ripard 
1431aa288248SMaxime Ripard static unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor,
1432aa288248SMaxime Ripard 				      unsigned long rate,
1433aa288248SMaxime Ripard 				      u8 *pll_prediv, u8 *pll_mult, u8 *sysdiv,
1434aa288248SMaxime Ripard 				      u8 *pll_rdiv, u8 *bit_div, u8 *pclk_div)
1435aa288248SMaxime Ripard {
1436aa288248SMaxime Ripard 	unsigned long _rate = rate * OV5640_PLL_ROOT_DIV * OV5640_BIT_DIV *
1437aa288248SMaxime Ripard 				OV5640_PCLK_ROOT_DIV;
1438aa288248SMaxime Ripard 
1439aa288248SMaxime Ripard 	_rate = ov5640_calc_sys_clk(sensor, _rate, pll_prediv, pll_mult,
1440aa288248SMaxime Ripard 				    sysdiv);
1441aa288248SMaxime Ripard 	*pll_rdiv = OV5640_PLL_ROOT_DIV;
1442aa288248SMaxime Ripard 	*bit_div = OV5640_BIT_DIV;
1443aa288248SMaxime Ripard 	*pclk_div = OV5640_PCLK_ROOT_DIV;
1444aa288248SMaxime Ripard 
1445aa288248SMaxime Ripard 	return _rate / *pll_rdiv / *bit_div / *pclk_div;
1446aa288248SMaxime Ripard }
1447aa288248SMaxime Ripard 
14486c957ed7SJacopo Mondi static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor)
1449aa288248SMaxime Ripard {
1450aa288248SMaxime Ripard 	u8 prediv, mult, sysdiv, pll_rdiv, bit_div, pclk_div;
14516c957ed7SJacopo Mondi 	u32 rate;
1452aa288248SMaxime Ripard 	int ret;
1453aa288248SMaxime Ripard 
14546c957ed7SJacopo Mondi 	rate = ov5640_calc_pixel_rate(sensor);
14556c957ed7SJacopo Mondi 	rate *= ov5640_code_to_bpp(sensor->fmt.code);
14566c957ed7SJacopo Mondi 	rate /= sensor->ep.bus.parallel.bus_width;
14576c957ed7SJacopo Mondi 
1458aa288248SMaxime Ripard 	ov5640_calc_pclk(sensor, rate, &prediv, &mult, &sysdiv, &pll_rdiv,
1459aa288248SMaxime Ripard 			 &bit_div, &pclk_div);
1460aa288248SMaxime Ripard 
1461aa288248SMaxime Ripard 	if (bit_div == 2)
1462aa288248SMaxime Ripard 		bit_div = 8;
1463aa288248SMaxime Ripard 
1464aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0,
1465aa288248SMaxime Ripard 			     0x0f, bit_div);
1466aa288248SMaxime Ripard 	if (ret)
1467aa288248SMaxime Ripard 		return ret;
1468aa288248SMaxime Ripard 
1469aa288248SMaxime Ripard 	/*
1470aa288248SMaxime Ripard 	 * We need to set sysdiv according to the clock, and to clear
1471aa288248SMaxime Ripard 	 * the MIPI divider.
1472aa288248SMaxime Ripard 	 */
1473aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1,
1474aa288248SMaxime Ripard 			     0xff, sysdiv << 4);
1475aa288248SMaxime Ripard 	if (ret)
1476aa288248SMaxime Ripard 		return ret;
1477aa288248SMaxime Ripard 
1478aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2,
1479aa288248SMaxime Ripard 			     0xff, mult);
1480aa288248SMaxime Ripard 	if (ret)
1481aa288248SMaxime Ripard 		return ret;
1482aa288248SMaxime Ripard 
1483aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3,
1484aa288248SMaxime Ripard 			     0x1f, prediv | ((pll_rdiv - 1) << 4));
1485aa288248SMaxime Ripard 	if (ret)
1486aa288248SMaxime Ripard 		return ret;
1487aa288248SMaxime Ripard 
1488aa288248SMaxime Ripard 	return ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x30,
1489aa288248SMaxime Ripard 			      (ilog2(pclk_div) << 4));
1490aa288248SMaxime Ripard }
1491aa288248SMaxime Ripard 
14927cb013b1SChen-Yu Tsai /* set JPEG framing sizes */
14937cb013b1SChen-Yu Tsai static int ov5640_set_jpeg_timings(struct ov5640_dev *sensor,
14947cb013b1SChen-Yu Tsai 				   const struct ov5640_mode_info *mode)
14957cb013b1SChen-Yu Tsai {
14967cb013b1SChen-Yu Tsai 	int ret;
14977cb013b1SChen-Yu Tsai 
14982b5c18f9SChen-Yu Tsai 	/*
14992b5c18f9SChen-Yu Tsai 	 * compression mode 3 timing
15002b5c18f9SChen-Yu Tsai 	 *
15012b5c18f9SChen-Yu Tsai 	 * Data is transmitted with programmable width (VFIFO_HSIZE).
15022b5c18f9SChen-Yu Tsai 	 * No padding done. Last line may have less data. Varying
15032b5c18f9SChen-Yu Tsai 	 * number of lines per frame, depending on amount of data.
15042b5c18f9SChen-Yu Tsai 	 */
15052b5c18f9SChen-Yu Tsai 	ret = ov5640_mod_reg(sensor, OV5640_REG_JPG_MODE_SELECT, 0x7, 0x3);
15062b5c18f9SChen-Yu Tsai 	if (ret < 0)
15072b5c18f9SChen-Yu Tsai 		return ret;
15082b5c18f9SChen-Yu Tsai 
15095113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_VFIFO_HSIZE, mode->width);
15107cb013b1SChen-Yu Tsai 	if (ret < 0)
15117cb013b1SChen-Yu Tsai 		return ret;
15127cb013b1SChen-Yu Tsai 
15135113d5b3SJacopo Mondi 	return ov5640_write_reg16(sensor, OV5640_REG_VFIFO_VSIZE, mode->height);
15147cb013b1SChen-Yu Tsai }
15157cb013b1SChen-Yu Tsai 
151619a81c14SSteve Longerbeam /* download ov5640 settings to sensor through i2c */
1517bad1774eSJacopo Mondi static int ov5640_set_timings(struct ov5640_dev *sensor,
1518bad1774eSJacopo Mondi 			      const struct ov5640_mode_info *mode)
1519bad1774eSJacopo Mondi {
15205113d5b3SJacopo Mondi 	const struct ov5640_timings *timings;
15215113d5b3SJacopo Mondi 	const struct v4l2_rect *analog_crop;
15225113d5b3SJacopo Mondi 	const struct v4l2_rect *crop;
1523bad1774eSJacopo Mondi 	int ret;
1524bad1774eSJacopo Mondi 
15257cb013b1SChen-Yu Tsai 	if (sensor->fmt.code == MEDIA_BUS_FMT_JPEG_1X8) {
15267cb013b1SChen-Yu Tsai 		ret = ov5640_set_jpeg_timings(sensor, mode);
15277cb013b1SChen-Yu Tsai 		if (ret < 0)
15287cb013b1SChen-Yu Tsai 			return ret;
15297cb013b1SChen-Yu Tsai 	}
15307cb013b1SChen-Yu Tsai 
15312de6bb97SJacopo Mondi 	timings = ov5640_timings(sensor, mode);
15325113d5b3SJacopo Mondi 	analog_crop = &timings->analog_crop;
15335113d5b3SJacopo Mondi 	crop = &timings->crop;
15345113d5b3SJacopo Mondi 
15353145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HS,
15363145efcdSJacopo Mondi 				 analog_crop->left);
1537bad1774eSJacopo Mondi 	if (ret < 0)
1538bad1774eSJacopo Mondi 		return ret;
1539bad1774eSJacopo Mondi 
15403145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VS,
15413145efcdSJacopo Mondi 				 analog_crop->top);
15423145efcdSJacopo Mondi 	if (ret < 0)
15433145efcdSJacopo Mondi 		return ret;
15443145efcdSJacopo Mondi 
15453145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HW,
15463145efcdSJacopo Mondi 				 analog_crop->left + analog_crop->width - 1);
15473145efcdSJacopo Mondi 	if (ret < 0)
15483145efcdSJacopo Mondi 		return ret;
15493145efcdSJacopo Mondi 
15503145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VH,
15513145efcdSJacopo Mondi 				 analog_crop->top + analog_crop->height - 1);
15523145efcdSJacopo Mondi 	if (ret < 0)
15533145efcdSJacopo Mondi 		return ret;
15543145efcdSJacopo Mondi 
15553145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HOFFS, crop->left);
15563145efcdSJacopo Mondi 	if (ret < 0)
15573145efcdSJacopo Mondi 		return ret;
15583145efcdSJacopo Mondi 
15593145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VOFFS, crop->top);
15603145efcdSJacopo Mondi 	if (ret < 0)
15613145efcdSJacopo Mondi 		return ret;
15623145efcdSJacopo Mondi 
15635113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->width);
15643145efcdSJacopo Mondi 	if (ret < 0)
15653145efcdSJacopo Mondi 		return ret;
15663145efcdSJacopo Mondi 
15675113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, mode->height);
1568bad1774eSJacopo Mondi 	if (ret < 0)
1569bad1774eSJacopo Mondi 		return ret;
1570bad1774eSJacopo Mondi 
15715113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, timings->htot);
1572bad1774eSJacopo Mondi 	if (ret < 0)
1573bad1774eSJacopo Mondi 		return ret;
1574bad1774eSJacopo Mondi 
15753145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS,
15765113d5b3SJacopo Mondi 				 mode->height + timings->vblank_def);
15773145efcdSJacopo Mondi 	if (ret < 0)
15783145efcdSJacopo Mondi 		return ret;
15793145efcdSJacopo Mondi 
15803145efcdSJacopo Mondi 	return 0;
1581bad1774eSJacopo Mondi }
1582bad1774eSJacopo Mondi 
1583e4359019SJacopo Mondi static void ov5640_load_regs(struct ov5640_dev *sensor,
1584e4359019SJacopo Mondi 			     const struct reg_value *regs, unsigned int regnum)
158519a81c14SSteve Longerbeam {
158619a81c14SSteve Longerbeam 	unsigned int i;
158719a81c14SSteve Longerbeam 	u32 delay_ms;
158819a81c14SSteve Longerbeam 	u16 reg_addr;
158919a81c14SSteve Longerbeam 	u8 mask, val;
159019a81c14SSteve Longerbeam 	int ret = 0;
159119a81c14SSteve Longerbeam 
1592e4359019SJacopo Mondi 	for (i = 0; i < regnum; ++i, ++regs) {
159319a81c14SSteve Longerbeam 		delay_ms = regs->delay_ms;
159419a81c14SSteve Longerbeam 		reg_addr = regs->reg_addr;
159519a81c14SSteve Longerbeam 		val = regs->val;
159619a81c14SSteve Longerbeam 		mask = regs->mask;
159719a81c14SSteve Longerbeam 
15983b987d70SLad Prabhakar 		/* remain in power down mode for DVP */
15993b987d70SLad Prabhakar 		if (regs->reg_addr == OV5640_REG_SYS_CTRL0 &&
16003b987d70SLad Prabhakar 		    val == OV5640_REG_SYS_CTRL0_SW_PWUP &&
16018e823f5cSJacopo Mondi 		    !ov5640_is_csi2(sensor))
16023b987d70SLad Prabhakar 			continue;
16033b987d70SLad Prabhakar 
160419a81c14SSteve Longerbeam 		if (mask)
160519a81c14SSteve Longerbeam 			ret = ov5640_mod_reg(sensor, reg_addr, mask, val);
160619a81c14SSteve Longerbeam 		else
160719a81c14SSteve Longerbeam 			ret = ov5640_write_reg(sensor, reg_addr, val);
160819a81c14SSteve Longerbeam 		if (ret)
160919a81c14SSteve Longerbeam 			break;
161019a81c14SSteve Longerbeam 
161119a81c14SSteve Longerbeam 		if (delay_ms)
161219a81c14SSteve Longerbeam 			usleep_range(1000 * delay_ms, 1000 * delay_ms + 100);
161319a81c14SSteve Longerbeam 	}
161419a81c14SSteve Longerbeam }
161519a81c14SSteve Longerbeam 
1616dc29a1c1SHugues Fruchet static int ov5640_set_autoexposure(struct ov5640_dev *sensor, bool on)
1617dc29a1c1SHugues Fruchet {
1618dc29a1c1SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
1619dc29a1c1SHugues Fruchet 			      BIT(0), on ? 0 : BIT(0));
1620dc29a1c1SHugues Fruchet }
1621dc29a1c1SHugues Fruchet 
162219a81c14SSteve Longerbeam /* read exposure, in number of line periods */
162319a81c14SSteve Longerbeam static int ov5640_get_exposure(struct ov5640_dev *sensor)
162419a81c14SSteve Longerbeam {
162519a81c14SSteve Longerbeam 	int exp, ret;
162619a81c14SSteve Longerbeam 	u8 temp;
162719a81c14SSteve Longerbeam 
162819a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_HI, &temp);
162919a81c14SSteve Longerbeam 	if (ret)
163019a81c14SSteve Longerbeam 		return ret;
163119a81c14SSteve Longerbeam 	exp = ((int)temp & 0x0f) << 16;
163219a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_MED, &temp);
163319a81c14SSteve Longerbeam 	if (ret)
163419a81c14SSteve Longerbeam 		return ret;
163519a81c14SSteve Longerbeam 	exp |= ((int)temp << 8);
163619a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_LO, &temp);
163719a81c14SSteve Longerbeam 	if (ret)
163819a81c14SSteve Longerbeam 		return ret;
163919a81c14SSteve Longerbeam 	exp |= (int)temp;
164019a81c14SSteve Longerbeam 
164119a81c14SSteve Longerbeam 	return exp >> 4;
164219a81c14SSteve Longerbeam }
164319a81c14SSteve Longerbeam 
164419a81c14SSteve Longerbeam /* write exposure, given number of line periods */
164519a81c14SSteve Longerbeam static int ov5640_set_exposure(struct ov5640_dev *sensor, u32 exposure)
164619a81c14SSteve Longerbeam {
164719a81c14SSteve Longerbeam 	int ret;
164819a81c14SSteve Longerbeam 
164919a81c14SSteve Longerbeam 	exposure <<= 4;
165019a81c14SSteve Longerbeam 
165119a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor,
165219a81c14SSteve Longerbeam 			       OV5640_REG_AEC_PK_EXPOSURE_LO,
165319a81c14SSteve Longerbeam 			       exposure & 0xff);
165419a81c14SSteve Longerbeam 	if (ret)
165519a81c14SSteve Longerbeam 		return ret;
165619a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor,
165719a81c14SSteve Longerbeam 			       OV5640_REG_AEC_PK_EXPOSURE_MED,
165819a81c14SSteve Longerbeam 			       (exposure >> 8) & 0xff);
165919a81c14SSteve Longerbeam 	if (ret)
166019a81c14SSteve Longerbeam 		return ret;
166119a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor,
166219a81c14SSteve Longerbeam 				OV5640_REG_AEC_PK_EXPOSURE_HI,
166319a81c14SSteve Longerbeam 				(exposure >> 16) & 0x0f);
166419a81c14SSteve Longerbeam }
166519a81c14SSteve Longerbeam 
166619a81c14SSteve Longerbeam static int ov5640_get_gain(struct ov5640_dev *sensor)
166719a81c14SSteve Longerbeam {
166819a81c14SSteve Longerbeam 	u16 gain;
166919a81c14SSteve Longerbeam 	int ret;
167019a81c14SSteve Longerbeam 
167119a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN, &gain);
167219a81c14SSteve Longerbeam 	if (ret)
167319a81c14SSteve Longerbeam 		return ret;
167419a81c14SSteve Longerbeam 
167519a81c14SSteve Longerbeam 	return gain & 0x3ff;
167619a81c14SSteve Longerbeam }
167719a81c14SSteve Longerbeam 
16783cca8ef5SHugues Fruchet static int ov5640_set_gain(struct ov5640_dev *sensor, int gain)
16793cca8ef5SHugues Fruchet {
16803cca8ef5SHugues Fruchet 	return ov5640_write_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN,
16813cca8ef5SHugues Fruchet 				  (u16)gain & 0x3ff);
16823cca8ef5SHugues Fruchet }
16833cca8ef5SHugues Fruchet 
16843cca8ef5SHugues Fruchet static int ov5640_set_autogain(struct ov5640_dev *sensor, bool on)
16853cca8ef5SHugues Fruchet {
16863cca8ef5SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
16873cca8ef5SHugues Fruchet 			      BIT(1), on ? 0 : BIT(1));
16883cca8ef5SHugues Fruchet }
16893cca8ef5SHugues Fruchet 
1690f22996dbSHugues Fruchet static int ov5640_set_stream_dvp(struct ov5640_dev *sensor, bool on)
1691f22996dbSHugues Fruchet {
16923b987d70SLad Prabhakar 	return ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0, on ?
16933b987d70SLad Prabhakar 				OV5640_REG_SYS_CTRL0_SW_PWUP :
16943b987d70SLad Prabhakar 				OV5640_REG_SYS_CTRL0_SW_PWDN);
1695f22996dbSHugues Fruchet }
1696f22996dbSHugues Fruchet 
1697f22996dbSHugues Fruchet static int ov5640_set_stream_mipi(struct ov5640_dev *sensor, bool on)
169819a81c14SSteve Longerbeam {
169919a81c14SSteve Longerbeam 	int ret;
170019a81c14SSteve Longerbeam 
1701aa4bb8b8SJacopo Mondi 	/*
1702aa4bb8b8SJacopo Mondi 	 * Enable/disable the MIPI interface
1703aa4bb8b8SJacopo Mondi 	 *
1704aa4bb8b8SJacopo Mondi 	 * 0x300e = on ? 0x45 : 0x40
1705aa4bb8b8SJacopo Mondi 	 *
1706aa4bb8b8SJacopo Mondi 	 * FIXME: the sensor manual (version 2.03) reports
1707aa4bb8b8SJacopo Mondi 	 * [7:5] = 000  : 1 data lane mode
1708aa4bb8b8SJacopo Mondi 	 * [7:5] = 001  : 2 data lanes mode
1709aa4bb8b8SJacopo Mondi 	 * But this settings do not work, while the following ones
1710aa4bb8b8SJacopo Mondi 	 * have been validated for 2 data lanes mode.
1711aa4bb8b8SJacopo Mondi 	 *
1712aa4bb8b8SJacopo Mondi 	 * [7:5] = 010	: 2 data lanes mode
1713aa4bb8b8SJacopo Mondi 	 * [4] = 0	: Power up MIPI HS Tx
1714aa4bb8b8SJacopo Mondi 	 * [3] = 0	: Power up MIPI LS Rx
1715aa4bb8b8SJacopo Mondi 	 * [2] = 1/0	: MIPI interface enable/disable
1716aa4bb8b8SJacopo Mondi 	 * [1:0] = 01/00: FIXME: 'debug'
1717aa4bb8b8SJacopo Mondi 	 */
1718aa4bb8b8SJacopo Mondi 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00,
1719aa4bb8b8SJacopo Mondi 			       on ? 0x45 : 0x40);
172019a81c14SSteve Longerbeam 	if (ret)
172119a81c14SSteve Longerbeam 		return ret;
172219a81c14SSteve Longerbeam 
172319a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_FRAME_CTRL01,
172419a81c14SSteve Longerbeam 				on ? 0x00 : 0x0f);
172519a81c14SSteve Longerbeam }
172619a81c14SSteve Longerbeam 
172719a81c14SSteve Longerbeam static int ov5640_get_sysclk(struct ov5640_dev *sensor)
172819a81c14SSteve Longerbeam {
172919a81c14SSteve Longerbeam 	 /* calculate sysclk */
173019a81c14SSteve Longerbeam 	u32 xvclk = sensor->xclk_freq / 10000;
173119a81c14SSteve Longerbeam 	u32 multiplier, prediv, VCO, sysdiv, pll_rdiv;
173219a81c14SSteve Longerbeam 	u32 sclk_rdiv_map[] = {1, 2, 4, 8};
173319a81c14SSteve Longerbeam 	u32 bit_div2x = 1, sclk_rdiv, sysclk;
173419a81c14SSteve Longerbeam 	u8 temp1, temp2;
173519a81c14SSteve Longerbeam 	int ret;
173619a81c14SSteve Longerbeam 
173719a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL0, &temp1);
173819a81c14SSteve Longerbeam 	if (ret)
173919a81c14SSteve Longerbeam 		return ret;
174019a81c14SSteve Longerbeam 	temp2 = temp1 & 0x0f;
174119a81c14SSteve Longerbeam 	if (temp2 == 8 || temp2 == 10)
174219a81c14SSteve Longerbeam 		bit_div2x = temp2 / 2;
174319a81c14SSteve Longerbeam 
174419a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL1, &temp1);
174519a81c14SSteve Longerbeam 	if (ret)
174619a81c14SSteve Longerbeam 		return ret;
174719a81c14SSteve Longerbeam 	sysdiv = temp1 >> 4;
174819a81c14SSteve Longerbeam 	if (sysdiv == 0)
174919a81c14SSteve Longerbeam 		sysdiv = 16;
175019a81c14SSteve Longerbeam 
175119a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL2, &temp1);
175219a81c14SSteve Longerbeam 	if (ret)
175319a81c14SSteve Longerbeam 		return ret;
175419a81c14SSteve Longerbeam 	multiplier = temp1;
175519a81c14SSteve Longerbeam 
175619a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL3, &temp1);
175719a81c14SSteve Longerbeam 	if (ret)
175819a81c14SSteve Longerbeam 		return ret;
175919a81c14SSteve Longerbeam 	prediv = temp1 & 0x0f;
176019a81c14SSteve Longerbeam 	pll_rdiv = ((temp1 >> 4) & 0x01) + 1;
176119a81c14SSteve Longerbeam 
176219a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, &temp1);
176319a81c14SSteve Longerbeam 	if (ret)
176419a81c14SSteve Longerbeam 		return ret;
176519a81c14SSteve Longerbeam 	temp2 = temp1 & 0x03;
176619a81c14SSteve Longerbeam 	sclk_rdiv = sclk_rdiv_map[temp2];
176719a81c14SSteve Longerbeam 
176819a81c14SSteve Longerbeam 	if (!prediv || !sysdiv || !pll_rdiv || !bit_div2x)
176919a81c14SSteve Longerbeam 		return -EINVAL;
177019a81c14SSteve Longerbeam 
177119a81c14SSteve Longerbeam 	VCO = xvclk * multiplier / prediv;
177219a81c14SSteve Longerbeam 
177319a81c14SSteve Longerbeam 	sysclk = VCO / sysdiv / pll_rdiv * 2 / bit_div2x / sclk_rdiv;
177419a81c14SSteve Longerbeam 
177519a81c14SSteve Longerbeam 	return sysclk;
177619a81c14SSteve Longerbeam }
177719a81c14SSteve Longerbeam 
177819a81c14SSteve Longerbeam static int ov5640_set_night_mode(struct ov5640_dev *sensor)
177919a81c14SSteve Longerbeam {
178019a81c14SSteve Longerbeam 	 /* read HTS from register settings */
178119a81c14SSteve Longerbeam 	u8 mode;
178219a81c14SSteve Longerbeam 	int ret;
178319a81c14SSteve Longerbeam 
178419a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_CTRL00, &mode);
178519a81c14SSteve Longerbeam 	if (ret)
178619a81c14SSteve Longerbeam 		return ret;
178719a81c14SSteve Longerbeam 	mode &= 0xfb;
178819a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL00, mode);
178919a81c14SSteve Longerbeam }
179019a81c14SSteve Longerbeam 
179119a81c14SSteve Longerbeam static int ov5640_get_hts(struct ov5640_dev *sensor)
179219a81c14SSteve Longerbeam {
179319a81c14SSteve Longerbeam 	/* read HTS from register settings */
179419a81c14SSteve Longerbeam 	u16 hts;
179519a81c14SSteve Longerbeam 	int ret;
179619a81c14SSteve Longerbeam 
179719a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_HTS, &hts);
179819a81c14SSteve Longerbeam 	if (ret)
179919a81c14SSteve Longerbeam 		return ret;
180019a81c14SSteve Longerbeam 	return hts;
180119a81c14SSteve Longerbeam }
180219a81c14SSteve Longerbeam 
180319a81c14SSteve Longerbeam static int ov5640_get_vts(struct ov5640_dev *sensor)
180419a81c14SSteve Longerbeam {
180519a81c14SSteve Longerbeam 	u16 vts;
180619a81c14SSteve Longerbeam 	int ret;
180719a81c14SSteve Longerbeam 
180819a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_VTS, &vts);
180919a81c14SSteve Longerbeam 	if (ret)
181019a81c14SSteve Longerbeam 		return ret;
181119a81c14SSteve Longerbeam 	return vts;
181219a81c14SSteve Longerbeam }
181319a81c14SSteve Longerbeam 
181419a81c14SSteve Longerbeam static int ov5640_set_vts(struct ov5640_dev *sensor, int vts)
181519a81c14SSteve Longerbeam {
181619a81c14SSteve Longerbeam 	return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, vts);
181719a81c14SSteve Longerbeam }
181819a81c14SSteve Longerbeam 
181919a81c14SSteve Longerbeam static int ov5640_get_light_freq(struct ov5640_dev *sensor)
182019a81c14SSteve Longerbeam {
182119a81c14SSteve Longerbeam 	/* get banding filter value */
182219a81c14SSteve Longerbeam 	int ret, light_freq = 0;
182319a81c14SSteve Longerbeam 	u8 temp, temp1;
182419a81c14SSteve Longerbeam 
182519a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL01, &temp);
182619a81c14SSteve Longerbeam 	if (ret)
182719a81c14SSteve Longerbeam 		return ret;
182819a81c14SSteve Longerbeam 
182919a81c14SSteve Longerbeam 	if (temp & 0x80) {
183019a81c14SSteve Longerbeam 		/* manual */
183119a81c14SSteve Longerbeam 		ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL00,
183219a81c14SSteve Longerbeam 				      &temp1);
183319a81c14SSteve Longerbeam 		if (ret)
183419a81c14SSteve Longerbeam 			return ret;
183519a81c14SSteve Longerbeam 		if (temp1 & 0x04) {
183619a81c14SSteve Longerbeam 			/* 50Hz */
183719a81c14SSteve Longerbeam 			light_freq = 50;
183819a81c14SSteve Longerbeam 		} else {
183919a81c14SSteve Longerbeam 			/* 60Hz */
184019a81c14SSteve Longerbeam 			light_freq = 60;
184119a81c14SSteve Longerbeam 		}
184219a81c14SSteve Longerbeam 	} else {
184319a81c14SSteve Longerbeam 		/* auto */
184419a81c14SSteve Longerbeam 		ret = ov5640_read_reg(sensor, OV5640_REG_SIGMADELTA_CTRL0C,
184519a81c14SSteve Longerbeam 				      &temp1);
184619a81c14SSteve Longerbeam 		if (ret)
184719a81c14SSteve Longerbeam 			return ret;
184819a81c14SSteve Longerbeam 
184919a81c14SSteve Longerbeam 		if (temp1 & 0x01) {
185019a81c14SSteve Longerbeam 			/* 50Hz */
185119a81c14SSteve Longerbeam 			light_freq = 50;
185219a81c14SSteve Longerbeam 		} else {
185319a81c14SSteve Longerbeam 			/* 60Hz */
185419a81c14SSteve Longerbeam 		}
185519a81c14SSteve Longerbeam 	}
185619a81c14SSteve Longerbeam 
185719a81c14SSteve Longerbeam 	return light_freq;
185819a81c14SSteve Longerbeam }
185919a81c14SSteve Longerbeam 
186019a81c14SSteve Longerbeam static int ov5640_set_bandingfilter(struct ov5640_dev *sensor)
186119a81c14SSteve Longerbeam {
186219a81c14SSteve Longerbeam 	u32 band_step60, max_band60, band_step50, max_band50, prev_vts;
186319a81c14SSteve Longerbeam 	int ret;
186419a81c14SSteve Longerbeam 
186519a81c14SSteve Longerbeam 	/* read preview PCLK */
186619a81c14SSteve Longerbeam 	ret = ov5640_get_sysclk(sensor);
186719a81c14SSteve Longerbeam 	if (ret < 0)
186819a81c14SSteve Longerbeam 		return ret;
186919a81c14SSteve Longerbeam 	if (ret == 0)
187019a81c14SSteve Longerbeam 		return -EINVAL;
187119a81c14SSteve Longerbeam 	sensor->prev_sysclk = ret;
187219a81c14SSteve Longerbeam 	/* read preview HTS */
187319a81c14SSteve Longerbeam 	ret = ov5640_get_hts(sensor);
187419a81c14SSteve Longerbeam 	if (ret < 0)
187519a81c14SSteve Longerbeam 		return ret;
187619a81c14SSteve Longerbeam 	if (ret == 0)
187719a81c14SSteve Longerbeam 		return -EINVAL;
187819a81c14SSteve Longerbeam 	sensor->prev_hts = ret;
187919a81c14SSteve Longerbeam 
188019a81c14SSteve Longerbeam 	/* read preview VTS */
188119a81c14SSteve Longerbeam 	ret = ov5640_get_vts(sensor);
188219a81c14SSteve Longerbeam 	if (ret < 0)
188319a81c14SSteve Longerbeam 		return ret;
188419a81c14SSteve Longerbeam 	prev_vts = ret;
188519a81c14SSteve Longerbeam 
188619a81c14SSteve Longerbeam 	/* calculate banding filter */
188719a81c14SSteve Longerbeam 	/* 60Hz */
188819a81c14SSteve Longerbeam 	band_step60 = sensor->prev_sysclk * 100 / sensor->prev_hts * 100 / 120;
188919a81c14SSteve Longerbeam 	ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B60_STEP, band_step60);
189019a81c14SSteve Longerbeam 	if (ret)
189119a81c14SSteve Longerbeam 		return ret;
189219a81c14SSteve Longerbeam 	if (!band_step60)
189319a81c14SSteve Longerbeam 		return -EINVAL;
189419a81c14SSteve Longerbeam 	max_band60 = (int)((prev_vts - 4) / band_step60);
189519a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0D, max_band60);
189619a81c14SSteve Longerbeam 	if (ret)
189719a81c14SSteve Longerbeam 		return ret;
189819a81c14SSteve Longerbeam 
189919a81c14SSteve Longerbeam 	/* 50Hz */
190019a81c14SSteve Longerbeam 	band_step50 = sensor->prev_sysclk * 100 / sensor->prev_hts;
190119a81c14SSteve Longerbeam 	ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B50_STEP, band_step50);
190219a81c14SSteve Longerbeam 	if (ret)
190319a81c14SSteve Longerbeam 		return ret;
190419a81c14SSteve Longerbeam 	if (!band_step50)
190519a81c14SSteve Longerbeam 		return -EINVAL;
190619a81c14SSteve Longerbeam 	max_band50 = (int)((prev_vts - 4) / band_step50);
190719a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0E, max_band50);
190819a81c14SSteve Longerbeam }
190919a81c14SSteve Longerbeam 
191019a81c14SSteve Longerbeam static int ov5640_set_ae_target(struct ov5640_dev *sensor, int target)
191119a81c14SSteve Longerbeam {
191219a81c14SSteve Longerbeam 	/* stable in high */
191319a81c14SSteve Longerbeam 	u32 fast_high, fast_low;
191419a81c14SSteve Longerbeam 	int ret;
191519a81c14SSteve Longerbeam 
191619a81c14SSteve Longerbeam 	sensor->ae_low = target * 23 / 25;	/* 0.92 */
191719a81c14SSteve Longerbeam 	sensor->ae_high = target * 27 / 25;	/* 1.08 */
191819a81c14SSteve Longerbeam 
191919a81c14SSteve Longerbeam 	fast_high = sensor->ae_high << 1;
192019a81c14SSteve Longerbeam 	if (fast_high > 255)
192119a81c14SSteve Longerbeam 		fast_high = 255;
192219a81c14SSteve Longerbeam 
192319a81c14SSteve Longerbeam 	fast_low = sensor->ae_low >> 1;
192419a81c14SSteve Longerbeam 
192519a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0F, sensor->ae_high);
192619a81c14SSteve Longerbeam 	if (ret)
192719a81c14SSteve Longerbeam 		return ret;
192819a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL10, sensor->ae_low);
192919a81c14SSteve Longerbeam 	if (ret)
193019a81c14SSteve Longerbeam 		return ret;
193119a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1B, sensor->ae_high);
193219a81c14SSteve Longerbeam 	if (ret)
193319a81c14SSteve Longerbeam 		return ret;
193419a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1E, sensor->ae_low);
193519a81c14SSteve Longerbeam 	if (ret)
193619a81c14SSteve Longerbeam 		return ret;
193719a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL11, fast_high);
193819a81c14SSteve Longerbeam 	if (ret)
193919a81c14SSteve Longerbeam 		return ret;
194019a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1F, fast_low);
194119a81c14SSteve Longerbeam }
194219a81c14SSteve Longerbeam 
1943c2c3f42dSHugues Fruchet static int ov5640_get_binning(struct ov5640_dev *sensor)
194419a81c14SSteve Longerbeam {
194519a81c14SSteve Longerbeam 	u8 temp;
194619a81c14SSteve Longerbeam 	int ret;
194719a81c14SSteve Longerbeam 
194819a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_TIMING_TC_REG21, &temp);
194919a81c14SSteve Longerbeam 	if (ret)
195019a81c14SSteve Longerbeam 		return ret;
1951c2c3f42dSHugues Fruchet 
1952c2c3f42dSHugues Fruchet 	return temp & BIT(0);
195319a81c14SSteve Longerbeam }
195419a81c14SSteve Longerbeam 
1955ce85705aSHugues Fruchet static int ov5640_set_binning(struct ov5640_dev *sensor, bool enable)
1956ce85705aSHugues Fruchet {
1957ce85705aSHugues Fruchet 	int ret;
1958ce85705aSHugues Fruchet 
1959ce85705aSHugues Fruchet 	/*
1960ce85705aSHugues Fruchet 	 * TIMING TC REG21:
1961ce85705aSHugues Fruchet 	 * - [0]:	Horizontal binning enable
1962ce85705aSHugues Fruchet 	 */
1963ce85705aSHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
1964ce85705aSHugues Fruchet 			     BIT(0), enable ? BIT(0) : 0);
1965ce85705aSHugues Fruchet 	if (ret)
1966ce85705aSHugues Fruchet 		return ret;
1967ce85705aSHugues Fruchet 	/*
1968ce85705aSHugues Fruchet 	 * TIMING TC REG20:
1969ce85705aSHugues Fruchet 	 * - [0]:	Undocumented, but hardcoded init sequences
1970ce85705aSHugues Fruchet 	 *		are always setting REG21/REG20 bit 0 to same value...
1971ce85705aSHugues Fruchet 	 */
1972ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20,
1973ce85705aSHugues Fruchet 			      BIT(0), enable ? BIT(0) : 0);
1974ce85705aSHugues Fruchet }
1975ce85705aSHugues Fruchet 
197619a81c14SSteve Longerbeam static int ov5640_set_virtual_channel(struct ov5640_dev *sensor)
197719a81c14SSteve Longerbeam {
19788670d70aSHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
197919a81c14SSteve Longerbeam 	u8 temp, channel = virtual_channel;
198019a81c14SSteve Longerbeam 	int ret;
198119a81c14SSteve Longerbeam 
19828670d70aSHugues Fruchet 	if (channel > 3) {
19838670d70aSHugues Fruchet 		dev_err(&client->dev,
19848670d70aSHugues Fruchet 			"%s: wrong virtual_channel parameter, expected (0..3), got %d\n",
19858670d70aSHugues Fruchet 			__func__, channel);
198619a81c14SSteve Longerbeam 		return -EINVAL;
19878670d70aSHugues Fruchet 	}
198819a81c14SSteve Longerbeam 
198919a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_DEBUG_MODE, &temp);
199019a81c14SSteve Longerbeam 	if (ret)
199119a81c14SSteve Longerbeam 		return ret;
199219a81c14SSteve Longerbeam 	temp &= ~(3 << 6);
199319a81c14SSteve Longerbeam 	temp |= (channel << 6);
199419a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_DEBUG_MODE, temp);
199519a81c14SSteve Longerbeam }
199619a81c14SSteve Longerbeam 
199719a81c14SSteve Longerbeam static const struct ov5640_mode_info *
1998*b6ae5022SJacopo Mondi ov5640_find_mode(struct ov5640_dev *sensor, int width, int height, bool nearest)
199919a81c14SSteve Longerbeam {
20003c4a7372SHugues Fruchet 	const struct ov5640_mode_info *mode;
200119a81c14SSteve Longerbeam 
2002086c25f8SMaxime Ripard 	mode = v4l2_find_nearest_size(ov5640_mode_data,
2003086c25f8SMaxime Ripard 				      ARRAY_SIZE(ov5640_mode_data),
20045113d5b3SJacopo Mondi 				      width, height, width, height);
200519a81c14SSteve Longerbeam 
20063c4a7372SHugues Fruchet 	if (!mode ||
20073145efcdSJacopo Mondi 	    (!nearest &&
20085113d5b3SJacopo Mondi 	     (mode->width != width || mode->height != height)))
20093c4a7372SHugues Fruchet 		return NULL;
201019a81c14SSteve Longerbeam 
201119a81c14SSteve Longerbeam 	return mode;
201219a81c14SSteve Longerbeam }
201319a81c14SSteve Longerbeam 
201419a81c14SSteve Longerbeam /*
201519a81c14SSteve Longerbeam  * sensor changes between scaling and subsampling, go through
201619a81c14SSteve Longerbeam  * exposure calculation
201719a81c14SSteve Longerbeam  */
201841d8d7f5SHugues Fruchet static int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor,
201941d8d7f5SHugues Fruchet 					 const struct ov5640_mode_info *mode)
202019a81c14SSteve Longerbeam {
202119a81c14SSteve Longerbeam 	u32 prev_shutter, prev_gain16;
202219a81c14SSteve Longerbeam 	u32 cap_shutter, cap_gain16;
202319a81c14SSteve Longerbeam 	u32 cap_sysclk, cap_hts, cap_vts;
202419a81c14SSteve Longerbeam 	u32 light_freq, cap_bandfilt, cap_maxband;
202519a81c14SSteve Longerbeam 	u32 cap_gain16_shutter;
202619a81c14SSteve Longerbeam 	u8 average;
202719a81c14SSteve Longerbeam 	int ret;
202819a81c14SSteve Longerbeam 
202941d8d7f5SHugues Fruchet 	if (!mode->reg_data)
203019a81c14SSteve Longerbeam 		return -EINVAL;
203119a81c14SSteve Longerbeam 
203219a81c14SSteve Longerbeam 	/* read preview shutter */
203319a81c14SSteve Longerbeam 	ret = ov5640_get_exposure(sensor);
203419a81c14SSteve Longerbeam 	if (ret < 0)
203519a81c14SSteve Longerbeam 		return ret;
203619a81c14SSteve Longerbeam 	prev_shutter = ret;
2037c2c3f42dSHugues Fruchet 	ret = ov5640_get_binning(sensor);
203819a81c14SSteve Longerbeam 	if (ret < 0)
203919a81c14SSteve Longerbeam 		return ret;
204019a81c14SSteve Longerbeam 	if (ret && mode->id != OV5640_MODE_720P_1280_720 &&
204119a81c14SSteve Longerbeam 	    mode->id != OV5640_MODE_1080P_1920_1080)
204219a81c14SSteve Longerbeam 		prev_shutter *= 2;
204319a81c14SSteve Longerbeam 
204419a81c14SSteve Longerbeam 	/* read preview gain */
204519a81c14SSteve Longerbeam 	ret = ov5640_get_gain(sensor);
204619a81c14SSteve Longerbeam 	if (ret < 0)
204719a81c14SSteve Longerbeam 		return ret;
204819a81c14SSteve Longerbeam 	prev_gain16 = ret;
204919a81c14SSteve Longerbeam 
205019a81c14SSteve Longerbeam 	/* get average */
205119a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AVG_READOUT, &average);
205219a81c14SSteve Longerbeam 	if (ret)
205319a81c14SSteve Longerbeam 		return ret;
205419a81c14SSteve Longerbeam 
205519a81c14SSteve Longerbeam 	/* turn off night mode for capture */
205619a81c14SSteve Longerbeam 	ret = ov5640_set_night_mode(sensor);
205719a81c14SSteve Longerbeam 	if (ret < 0)
205819a81c14SSteve Longerbeam 		return ret;
205919a81c14SSteve Longerbeam 
206019a81c14SSteve Longerbeam 	/* Write capture setting */
2061e4359019SJacopo Mondi 	ov5640_load_regs(sensor, mode->reg_data, mode->reg_data_size);
2062e4359019SJacopo Mondi 	ret = ov5640_set_timings(sensor, mode);
206319a81c14SSteve Longerbeam 	if (ret < 0)
206419a81c14SSteve Longerbeam 		return ret;
206519a81c14SSteve Longerbeam 
206619a81c14SSteve Longerbeam 	/* read capture VTS */
206719a81c14SSteve Longerbeam 	ret = ov5640_get_vts(sensor);
206819a81c14SSteve Longerbeam 	if (ret < 0)
206919a81c14SSteve Longerbeam 		return ret;
207019a81c14SSteve Longerbeam 	cap_vts = ret;
207119a81c14SSteve Longerbeam 	ret = ov5640_get_hts(sensor);
207219a81c14SSteve Longerbeam 	if (ret < 0)
207319a81c14SSteve Longerbeam 		return ret;
207419a81c14SSteve Longerbeam 	if (ret == 0)
207519a81c14SSteve Longerbeam 		return -EINVAL;
207619a81c14SSteve Longerbeam 	cap_hts = ret;
207719a81c14SSteve Longerbeam 
207819a81c14SSteve Longerbeam 	ret = ov5640_get_sysclk(sensor);
207919a81c14SSteve Longerbeam 	if (ret < 0)
208019a81c14SSteve Longerbeam 		return ret;
208119a81c14SSteve Longerbeam 	if (ret == 0)
208219a81c14SSteve Longerbeam 		return -EINVAL;
208319a81c14SSteve Longerbeam 	cap_sysclk = ret;
208419a81c14SSteve Longerbeam 
208519a81c14SSteve Longerbeam 	/* calculate capture banding filter */
208619a81c14SSteve Longerbeam 	ret = ov5640_get_light_freq(sensor);
208719a81c14SSteve Longerbeam 	if (ret < 0)
208819a81c14SSteve Longerbeam 		return ret;
208919a81c14SSteve Longerbeam 	light_freq = ret;
209019a81c14SSteve Longerbeam 
209119a81c14SSteve Longerbeam 	if (light_freq == 60) {
209219a81c14SSteve Longerbeam 		/* 60Hz */
209319a81c14SSteve Longerbeam 		cap_bandfilt = cap_sysclk * 100 / cap_hts * 100 / 120;
209419a81c14SSteve Longerbeam 	} else {
209519a81c14SSteve Longerbeam 		/* 50Hz */
209619a81c14SSteve Longerbeam 		cap_bandfilt = cap_sysclk * 100 / cap_hts;
209719a81c14SSteve Longerbeam 	}
209819a81c14SSteve Longerbeam 
209919a81c14SSteve Longerbeam 	if (!sensor->prev_sysclk) {
210019a81c14SSteve Longerbeam 		ret = ov5640_get_sysclk(sensor);
210119a81c14SSteve Longerbeam 		if (ret < 0)
210219a81c14SSteve Longerbeam 			return ret;
210319a81c14SSteve Longerbeam 		if (ret == 0)
210419a81c14SSteve Longerbeam 			return -EINVAL;
210519a81c14SSteve Longerbeam 		sensor->prev_sysclk = ret;
210619a81c14SSteve Longerbeam 	}
210719a81c14SSteve Longerbeam 
210819a81c14SSteve Longerbeam 	if (!cap_bandfilt)
210919a81c14SSteve Longerbeam 		return -EINVAL;
211019a81c14SSteve Longerbeam 
211119a81c14SSteve Longerbeam 	cap_maxband = (int)((cap_vts - 4) / cap_bandfilt);
211219a81c14SSteve Longerbeam 
211319a81c14SSteve Longerbeam 	/* calculate capture shutter/gain16 */
211419a81c14SSteve Longerbeam 	if (average > sensor->ae_low && average < sensor->ae_high) {
211519a81c14SSteve Longerbeam 		/* in stable range */
211619a81c14SSteve Longerbeam 		cap_gain16_shutter =
211719a81c14SSteve Longerbeam 			prev_gain16 * prev_shutter *
211819a81c14SSteve Longerbeam 			cap_sysclk / sensor->prev_sysclk *
211919a81c14SSteve Longerbeam 			sensor->prev_hts / cap_hts *
212019a81c14SSteve Longerbeam 			sensor->ae_target / average;
212119a81c14SSteve Longerbeam 	} else {
212219a81c14SSteve Longerbeam 		cap_gain16_shutter =
212319a81c14SSteve Longerbeam 			prev_gain16 * prev_shutter *
212419a81c14SSteve Longerbeam 			cap_sysclk / sensor->prev_sysclk *
212519a81c14SSteve Longerbeam 			sensor->prev_hts / cap_hts;
212619a81c14SSteve Longerbeam 	}
212719a81c14SSteve Longerbeam 
212819a81c14SSteve Longerbeam 	/* gain to shutter */
212919a81c14SSteve Longerbeam 	if (cap_gain16_shutter < (cap_bandfilt * 16)) {
213019a81c14SSteve Longerbeam 		/* shutter < 1/100 */
213119a81c14SSteve Longerbeam 		cap_shutter = cap_gain16_shutter / 16;
213219a81c14SSteve Longerbeam 		if (cap_shutter < 1)
213319a81c14SSteve Longerbeam 			cap_shutter = 1;
213419a81c14SSteve Longerbeam 
213519a81c14SSteve Longerbeam 		cap_gain16 = cap_gain16_shutter / cap_shutter;
213619a81c14SSteve Longerbeam 		if (cap_gain16 < 16)
213719a81c14SSteve Longerbeam 			cap_gain16 = 16;
213819a81c14SSteve Longerbeam 	} else {
213919a81c14SSteve Longerbeam 		if (cap_gain16_shutter > (cap_bandfilt * cap_maxband * 16)) {
214019a81c14SSteve Longerbeam 			/* exposure reach max */
214119a81c14SSteve Longerbeam 			cap_shutter = cap_bandfilt * cap_maxband;
214219a81c14SSteve Longerbeam 			if (!cap_shutter)
214319a81c14SSteve Longerbeam 				return -EINVAL;
214419a81c14SSteve Longerbeam 
214519a81c14SSteve Longerbeam 			cap_gain16 = cap_gain16_shutter / cap_shutter;
214619a81c14SSteve Longerbeam 		} else {
214719a81c14SSteve Longerbeam 			/* 1/100 < (cap_shutter = n/100) =< max */
214819a81c14SSteve Longerbeam 			cap_shutter =
214919a81c14SSteve Longerbeam 				((int)(cap_gain16_shutter / 16 / cap_bandfilt))
215019a81c14SSteve Longerbeam 				* cap_bandfilt;
215119a81c14SSteve Longerbeam 			if (!cap_shutter)
215219a81c14SSteve Longerbeam 				return -EINVAL;
215319a81c14SSteve Longerbeam 
215419a81c14SSteve Longerbeam 			cap_gain16 = cap_gain16_shutter / cap_shutter;
215519a81c14SSteve Longerbeam 		}
215619a81c14SSteve Longerbeam 	}
215719a81c14SSteve Longerbeam 
215819a81c14SSteve Longerbeam 	/* set capture gain */
21593cca8ef5SHugues Fruchet 	ret = ov5640_set_gain(sensor, cap_gain16);
216019a81c14SSteve Longerbeam 	if (ret)
216119a81c14SSteve Longerbeam 		return ret;
216219a81c14SSteve Longerbeam 
216319a81c14SSteve Longerbeam 	/* write capture shutter */
216419a81c14SSteve Longerbeam 	if (cap_shutter > (cap_vts - 4)) {
216519a81c14SSteve Longerbeam 		cap_vts = cap_shutter + 4;
216619a81c14SSteve Longerbeam 		ret = ov5640_set_vts(sensor, cap_vts);
216719a81c14SSteve Longerbeam 		if (ret < 0)
216819a81c14SSteve Longerbeam 			return ret;
216919a81c14SSteve Longerbeam 	}
217019a81c14SSteve Longerbeam 
217119a81c14SSteve Longerbeam 	/* set exposure */
21723cca8ef5SHugues Fruchet 	return ov5640_set_exposure(sensor, cap_shutter);
217319a81c14SSteve Longerbeam }
217419a81c14SSteve Longerbeam 
217519a81c14SSteve Longerbeam /*
217619a81c14SSteve Longerbeam  * if sensor changes inside scaling or subsampling
217719a81c14SSteve Longerbeam  * change mode directly
217819a81c14SSteve Longerbeam  */
217919a81c14SSteve Longerbeam static int ov5640_set_mode_direct(struct ov5640_dev *sensor,
21803cca8ef5SHugues Fruchet 				  const struct ov5640_mode_info *mode)
218119a81c14SSteve Longerbeam {
218241d8d7f5SHugues Fruchet 	if (!mode->reg_data)
218319a81c14SSteve Longerbeam 		return -EINVAL;
218419a81c14SSteve Longerbeam 
218519a81c14SSteve Longerbeam 	/* Write capture setting */
2186e4359019SJacopo Mondi 	ov5640_load_regs(sensor, mode->reg_data, mode->reg_data_size);
2187e4359019SJacopo Mondi 	return ov5640_set_timings(sensor, mode);
218819a81c14SSteve Longerbeam }
218919a81c14SSteve Longerbeam 
2190985cdcb0SHugues Fruchet static int ov5640_set_mode(struct ov5640_dev *sensor)
219119a81c14SSteve Longerbeam {
219219a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode = sensor->current_mode;
2193985cdcb0SHugues Fruchet 	const struct ov5640_mode_info *orig_mode = sensor->last_mode;
219419a81c14SSteve Longerbeam 	enum ov5640_downsize_mode dn_mode, orig_dn_mode;
21953cca8ef5SHugues Fruchet 	bool auto_gain = sensor->ctrls.auto_gain->val == 1;
2196dc29a1c1SHugues Fruchet 	bool auto_exp =  sensor->ctrls.auto_exp->val == V4L2_EXPOSURE_AUTO;
219719a81c14SSteve Longerbeam 	int ret;
219819a81c14SSteve Longerbeam 
219919a81c14SSteve Longerbeam 	dn_mode = mode->dn_mode;
220019a81c14SSteve Longerbeam 	orig_dn_mode = orig_mode->dn_mode;
220119a81c14SSteve Longerbeam 
220219a81c14SSteve Longerbeam 	/* auto gain and exposure must be turned off when changing modes */
22033cca8ef5SHugues Fruchet 	if (auto_gain) {
22043cca8ef5SHugues Fruchet 		ret = ov5640_set_autogain(sensor, false);
220519a81c14SSteve Longerbeam 		if (ret)
220619a81c14SSteve Longerbeam 			return ret;
22073cca8ef5SHugues Fruchet 	}
2208bf4a4b51SMaxime Ripard 
22093cca8ef5SHugues Fruchet 	if (auto_exp) {
2210dc29a1c1SHugues Fruchet 		ret = ov5640_set_autoexposure(sensor, false);
221119a81c14SSteve Longerbeam 		if (ret)
22123cca8ef5SHugues Fruchet 			goto restore_auto_gain;
22133cca8ef5SHugues Fruchet 	}
221419a81c14SSteve Longerbeam 
22156c957ed7SJacopo Mondi 	if (ov5640_is_csi2(sensor))
22166c957ed7SJacopo Mondi 		ret = ov5640_set_mipi_pclk(sensor);
22176c957ed7SJacopo Mondi 	else
22186c957ed7SJacopo Mondi 		ret = ov5640_set_dvp_pclk(sensor);
2219aa288248SMaxime Ripard 	if (ret < 0)
2220aa288248SMaxime Ripard 		return 0;
2221aa288248SMaxime Ripard 
222219a81c14SSteve Longerbeam 	if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) ||
222319a81c14SSteve Longerbeam 	    (dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) {
222419a81c14SSteve Longerbeam 		/*
222519a81c14SSteve Longerbeam 		 * change between subsampling and scaling
22263cca8ef5SHugues Fruchet 		 * go through exposure calculation
222719a81c14SSteve Longerbeam 		 */
222819a81c14SSteve Longerbeam 		ret = ov5640_set_mode_exposure_calc(sensor, mode);
222919a81c14SSteve Longerbeam 	} else {
223019a81c14SSteve Longerbeam 		/*
223119a81c14SSteve Longerbeam 		 * change inside subsampling or scaling
223219a81c14SSteve Longerbeam 		 * download firmware directly
223319a81c14SSteve Longerbeam 		 */
22343cca8ef5SHugues Fruchet 		ret = ov5640_set_mode_direct(sensor, mode);
223519a81c14SSteve Longerbeam 	}
223619a81c14SSteve Longerbeam 	if (ret < 0)
22373cca8ef5SHugues Fruchet 		goto restore_auto_exp_gain;
22383cca8ef5SHugues Fruchet 
22393cca8ef5SHugues Fruchet 	/* restore auto gain and exposure */
22403cca8ef5SHugues Fruchet 	if (auto_gain)
22413cca8ef5SHugues Fruchet 		ov5640_set_autogain(sensor, true);
22423cca8ef5SHugues Fruchet 	if (auto_exp)
22433cca8ef5SHugues Fruchet 		ov5640_set_autoexposure(sensor, true);
224419a81c14SSteve Longerbeam 
2245ce85705aSHugues Fruchet 	ret = ov5640_set_binning(sensor, dn_mode != SCALING);
2246ce85705aSHugues Fruchet 	if (ret < 0)
2247ce85705aSHugues Fruchet 		return ret;
224819a81c14SSteve Longerbeam 	ret = ov5640_set_ae_target(sensor, sensor->ae_target);
224919a81c14SSteve Longerbeam 	if (ret < 0)
225019a81c14SSteve Longerbeam 		return ret;
225119a81c14SSteve Longerbeam 	ret = ov5640_get_light_freq(sensor);
225219a81c14SSteve Longerbeam 	if (ret < 0)
225319a81c14SSteve Longerbeam 		return ret;
225419a81c14SSteve Longerbeam 	ret = ov5640_set_bandingfilter(sensor);
225519a81c14SSteve Longerbeam 	if (ret < 0)
225619a81c14SSteve Longerbeam 		return ret;
225719a81c14SSteve Longerbeam 	ret = ov5640_set_virtual_channel(sensor);
225819a81c14SSteve Longerbeam 	if (ret < 0)
225919a81c14SSteve Longerbeam 		return ret;
226019a81c14SSteve Longerbeam 
226119a81c14SSteve Longerbeam 	sensor->pending_mode_change = false;
2262985cdcb0SHugues Fruchet 	sensor->last_mode = mode;
226319a81c14SSteve Longerbeam 
226419a81c14SSteve Longerbeam 	return 0;
22653cca8ef5SHugues Fruchet 
22663cca8ef5SHugues Fruchet restore_auto_exp_gain:
22673cca8ef5SHugues Fruchet 	if (auto_exp)
22683cca8ef5SHugues Fruchet 		ov5640_set_autoexposure(sensor, true);
22693cca8ef5SHugues Fruchet restore_auto_gain:
22703cca8ef5SHugues Fruchet 	if (auto_gain)
22713cca8ef5SHugues Fruchet 		ov5640_set_autogain(sensor, true);
22723cca8ef5SHugues Fruchet 
22733cca8ef5SHugues Fruchet 	return ret;
227419a81c14SSteve Longerbeam }
227519a81c14SSteve Longerbeam 
227619ad26f9SAkinobu Mita static int ov5640_set_framefmt(struct ov5640_dev *sensor,
227719ad26f9SAkinobu Mita 			       struct v4l2_mbus_framefmt *format);
227819ad26f9SAkinobu Mita 
227919a81c14SSteve Longerbeam /* restore the last set video mode after chip power-on */
228019a81c14SSteve Longerbeam static int ov5640_restore_mode(struct ov5640_dev *sensor)
228119a81c14SSteve Longerbeam {
228219a81c14SSteve Longerbeam 	int ret;
228319a81c14SSteve Longerbeam 
228419a81c14SSteve Longerbeam 	/* first load the initial register values */
2285e4359019SJacopo Mondi 	ov5640_load_regs(sensor, ov5640_init_setting,
2286e4359019SJacopo Mondi 			 ARRAY_SIZE(ov5640_init_setting));
228719a81c14SSteve Longerbeam 
22888f57c2f8SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
22897851fe7aSMaxime Ripard 			     (ilog2(OV5640_SCLK2X_ROOT_DIV) << 2) |
22907851fe7aSMaxime Ripard 			     ilog2(OV5640_SCLK_ROOT_DIV));
22918f57c2f8SMaxime Ripard 	if (ret)
22928f57c2f8SMaxime Ripard 		return ret;
22938f57c2f8SMaxime Ripard 
229419a81c14SSteve Longerbeam 	/* now restore the last capture mode */
2295985cdcb0SHugues Fruchet 	ret = ov5640_set_mode(sensor);
229619ad26f9SAkinobu Mita 	if (ret < 0)
229719ad26f9SAkinobu Mita 		return ret;
229819ad26f9SAkinobu Mita 
229919ad26f9SAkinobu Mita 	return ov5640_set_framefmt(sensor, &sensor->fmt);
230019a81c14SSteve Longerbeam }
230119a81c14SSteve Longerbeam 
230219a81c14SSteve Longerbeam static void ov5640_power(struct ov5640_dev *sensor, bool enable)
230319a81c14SSteve Longerbeam {
23041fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->pwdn_gpio, enable ? 0 : 1);
230519a81c14SSteve Longerbeam }
230619a81c14SSteve Longerbeam 
230719a81c14SSteve Longerbeam static void ov5640_reset(struct ov5640_dev *sensor)
230819a81c14SSteve Longerbeam {
230919a81c14SSteve Longerbeam 	if (!sensor->reset_gpio)
231019a81c14SSteve Longerbeam 		return;
231119a81c14SSteve Longerbeam 
23121fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 0);
231319a81c14SSteve Longerbeam 
231419a81c14SSteve Longerbeam 	/* camera power cycle */
231519a81c14SSteve Longerbeam 	ov5640_power(sensor, false);
231619a81c14SSteve Longerbeam 	usleep_range(5000, 10000);
231719a81c14SSteve Longerbeam 	ov5640_power(sensor, true);
231819a81c14SSteve Longerbeam 	usleep_range(5000, 10000);
231919a81c14SSteve Longerbeam 
23201fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 1);
232119a81c14SSteve Longerbeam 	usleep_range(1000, 2000);
232219a81c14SSteve Longerbeam 
23231fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 0);
23241d4c41f3SLoic Poulain 	usleep_range(20000, 25000);
232519a81c14SSteve Longerbeam }
232619a81c14SSteve Longerbeam 
23270f7acb52SHugues Fruchet static int ov5640_set_power_on(struct ov5640_dev *sensor)
232819a81c14SSteve Longerbeam {
23290f7acb52SHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
23300f7acb52SHugues Fruchet 	int ret;
233119a81c14SSteve Longerbeam 
23320f7acb52SHugues Fruchet 	ret = clk_prepare_enable(sensor->xclk);
23330f7acb52SHugues Fruchet 	if (ret) {
23340f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to enable clock\n",
23350f7acb52SHugues Fruchet 			__func__);
23360f7acb52SHugues Fruchet 		return ret;
23370f7acb52SHugues Fruchet 	}
233819a81c14SSteve Longerbeam 
233919a81c14SSteve Longerbeam 	ret = regulator_bulk_enable(OV5640_NUM_SUPPLIES,
234019a81c14SSteve Longerbeam 				    sensor->supplies);
23410f7acb52SHugues Fruchet 	if (ret) {
23420f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to enable regulators\n",
23430f7acb52SHugues Fruchet 			__func__);
234419a81c14SSteve Longerbeam 		goto xclk_off;
23450f7acb52SHugues Fruchet 	}
234619a81c14SSteve Longerbeam 
234719a81c14SSteve Longerbeam 	ov5640_reset(sensor);
234819a81c14SSteve Longerbeam 	ov5640_power(sensor, true);
234919a81c14SSteve Longerbeam 
235019a81c14SSteve Longerbeam 	ret = ov5640_init_slave_id(sensor);
235119a81c14SSteve Longerbeam 	if (ret)
235219a81c14SSteve Longerbeam 		goto power_off;
235319a81c14SSteve Longerbeam 
23540f7acb52SHugues Fruchet 	return 0;
23550f7acb52SHugues Fruchet 
23560f7acb52SHugues Fruchet power_off:
23570f7acb52SHugues Fruchet 	ov5640_power(sensor, false);
23580f7acb52SHugues Fruchet 	regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies);
23590f7acb52SHugues Fruchet xclk_off:
23600f7acb52SHugues Fruchet 	clk_disable_unprepare(sensor->xclk);
23610f7acb52SHugues Fruchet 	return ret;
23620f7acb52SHugues Fruchet }
23630f7acb52SHugues Fruchet 
23640f7acb52SHugues Fruchet static void ov5640_set_power_off(struct ov5640_dev *sensor)
23650f7acb52SHugues Fruchet {
23660f7acb52SHugues Fruchet 	ov5640_power(sensor, false);
23670f7acb52SHugues Fruchet 	regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies);
23680f7acb52SHugues Fruchet 	clk_disable_unprepare(sensor->xclk);
23690f7acb52SHugues Fruchet }
23700f7acb52SHugues Fruchet 
2371b1751ae6SLad Prabhakar static int ov5640_set_power_mipi(struct ov5640_dev *sensor, bool on)
2372b1751ae6SLad Prabhakar {
2373b1751ae6SLad Prabhakar 	int ret;
2374b1751ae6SLad Prabhakar 
2375b1751ae6SLad Prabhakar 	if (!on) {
2376b1751ae6SLad Prabhakar 		/* Reset MIPI bus settings to their default values. */
2377b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
2378b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x04);
2379b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x00);
2380b1751ae6SLad Prabhakar 		return 0;
2381b1751ae6SLad Prabhakar 	}
2382b1751ae6SLad Prabhakar 
2383b1751ae6SLad Prabhakar 	/*
2384b1751ae6SLad Prabhakar 	 * Power up MIPI HS Tx and LS Rx; 2 data lanes mode
2385b1751ae6SLad Prabhakar 	 *
2386b1751ae6SLad Prabhakar 	 * 0x300e = 0x40
2387b1751ae6SLad Prabhakar 	 * [7:5] = 010	: 2 data lanes mode (see FIXME note in
2388b1751ae6SLad Prabhakar 	 *		  "ov5640_set_stream_mipi()")
2389b1751ae6SLad Prabhakar 	 * [4] = 0	: Power up MIPI HS Tx
2390b1751ae6SLad Prabhakar 	 * [3] = 0	: Power up MIPI LS Rx
2391b1751ae6SLad Prabhakar 	 * [2] = 0	: MIPI interface disabled
2392b1751ae6SLad Prabhakar 	 */
2393b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x40);
2394b1751ae6SLad Prabhakar 	if (ret)
2395b1751ae6SLad Prabhakar 		return ret;
2396b1751ae6SLad Prabhakar 
2397b1751ae6SLad Prabhakar 	/*
2398b1751ae6SLad Prabhakar 	 * Gate clock and set LP11 in 'no packets mode' (idle)
2399b1751ae6SLad Prabhakar 	 *
2400b1751ae6SLad Prabhakar 	 * 0x4800 = 0x24
2401b1751ae6SLad Prabhakar 	 * [5] = 1	: Gate clock when 'no packets'
2402b1751ae6SLad Prabhakar 	 * [2] = 1	: MIPI bus in LP11 when 'no packets'
2403b1751ae6SLad Prabhakar 	 */
2404b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x24);
2405b1751ae6SLad Prabhakar 	if (ret)
2406b1751ae6SLad Prabhakar 		return ret;
2407b1751ae6SLad Prabhakar 
2408b1751ae6SLad Prabhakar 	/*
2409b1751ae6SLad Prabhakar 	 * Set data lanes and clock in LP11 when 'sleeping'
2410b1751ae6SLad Prabhakar 	 *
2411b1751ae6SLad Prabhakar 	 * 0x3019 = 0x70
2412b1751ae6SLad Prabhakar 	 * [6] = 1	: MIPI data lane 2 in LP11 when 'sleeping'
2413b1751ae6SLad Prabhakar 	 * [5] = 1	: MIPI data lane 1 in LP11 when 'sleeping'
2414b1751ae6SLad Prabhakar 	 * [4] = 1	: MIPI clock lane in LP11 when 'sleeping'
2415b1751ae6SLad Prabhakar 	 */
2416b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x70);
2417b1751ae6SLad Prabhakar 	if (ret)
2418b1751ae6SLad Prabhakar 		return ret;
2419b1751ae6SLad Prabhakar 
2420b1751ae6SLad Prabhakar 	/* Give lanes some time to coax into LP11 state. */
2421b1751ae6SLad Prabhakar 	usleep_range(500, 1000);
2422b1751ae6SLad Prabhakar 
2423b1751ae6SLad Prabhakar 	return 0;
2424b1751ae6SLad Prabhakar }
2425b1751ae6SLad Prabhakar 
2426576f5d4bSLad Prabhakar static int ov5640_set_power_dvp(struct ov5640_dev *sensor, bool on)
2427576f5d4bSLad Prabhakar {
2428311a6408SLad Prabhakar 	unsigned int flags = sensor->ep.bus.parallel.flags;
242968579b32SHugues Fruchet 	bool bt656 = sensor->ep.bus_type == V4L2_MBUS_BT656;
243068579b32SHugues Fruchet 	u8 polarities = 0;
2431576f5d4bSLad Prabhakar 	int ret;
2432576f5d4bSLad Prabhakar 
2433576f5d4bSLad Prabhakar 	if (!on) {
2434576f5d4bSLad Prabhakar 		/* Reset settings to their default values. */
243568579b32SHugues Fruchet 		ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00, 0x00);
2436311a6408SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
2437311a6408SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, 0x20);
2438576f5d4bSLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01, 0x00);
2439576f5d4bSLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0x00);
2440576f5d4bSLad Prabhakar 		return 0;
2441576f5d4bSLad Prabhakar 	}
2442576f5d4bSLad Prabhakar 
2443576f5d4bSLad Prabhakar 	/*
2444311a6408SLad Prabhakar 	 * Note about parallel port configuration.
2445311a6408SLad Prabhakar 	 *
2446311a6408SLad Prabhakar 	 * When configured in parallel mode, the OV5640 will
2447311a6408SLad Prabhakar 	 * output 10 bits data on DVP data lines [9:0].
2448311a6408SLad Prabhakar 	 * If only 8 bits data are wanted, the 8 bits data lines
2449311a6408SLad Prabhakar 	 * of the camera interface must be physically connected
2450311a6408SLad Prabhakar 	 * on the DVP data lines [9:2].
2451311a6408SLad Prabhakar 	 *
2452311a6408SLad Prabhakar 	 * Control lines polarity can be configured through
2453311a6408SLad Prabhakar 	 * devicetree endpoint control lines properties.
2454311a6408SLad Prabhakar 	 * If no endpoint control lines properties are set,
2455311a6408SLad Prabhakar 	 * polarity will be as below:
2456311a6408SLad Prabhakar 	 * - VSYNC:	active high
2457311a6408SLad Prabhakar 	 * - HREF:	active low
2458311a6408SLad Prabhakar 	 * - PCLK:	active low
245968579b32SHugues Fruchet 	 *
246068579b32SHugues Fruchet 	 * VSYNC & HREF are not configured if BT656 bus mode is selected
2461311a6408SLad Prabhakar 	 */
246268579b32SHugues Fruchet 
246368579b32SHugues Fruchet 	/*
246468579b32SHugues Fruchet 	 * BT656 embedded synchronization configuration
246568579b32SHugues Fruchet 	 *
246668579b32SHugues Fruchet 	 * CCIR656 CTRL00
246768579b32SHugues Fruchet 	 * - [7]:	SYNC code selection (0: auto generate sync code,
246868579b32SHugues Fruchet 	 *		1: sync code from regs 0x4732-0x4735)
246968579b32SHugues Fruchet 	 * - [6]:	f value in CCIR656 SYNC code when fixed f value
247068579b32SHugues Fruchet 	 * - [5]:	Fixed f value
247168579b32SHugues Fruchet 	 * - [4:3]:	Blank toggle data options (00: data=1'h040/1'h200,
247268579b32SHugues Fruchet 	 *		01: data from regs 0x4736-0x4738, 10: always keep 0)
247368579b32SHugues Fruchet 	 * - [1]:	Clip data disable
247468579b32SHugues Fruchet 	 * - [0]:	CCIR656 mode enable
247568579b32SHugues Fruchet 	 *
247668579b32SHugues Fruchet 	 * Default CCIR656 SAV/EAV mode with default codes
247768579b32SHugues Fruchet 	 * SAV=0xff000080 & EAV=0xff00009d is enabled here with settings:
247868579b32SHugues Fruchet 	 * - CCIR656 mode enable
247968579b32SHugues Fruchet 	 * - auto generation of sync codes
248068579b32SHugues Fruchet 	 * - blank toggle data 1'h040/1'h200
248168579b32SHugues Fruchet 	 * - clip reserved data (0x00 & 0xff changed to 0x01 & 0xfe)
248268579b32SHugues Fruchet 	 */
248368579b32SHugues Fruchet 	ret = ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00,
248468579b32SHugues Fruchet 			       bt656 ? 0x01 : 0x00);
248568579b32SHugues Fruchet 	if (ret)
248668579b32SHugues Fruchet 		return ret;
248768579b32SHugues Fruchet 
2488311a6408SLad Prabhakar 	/*
2489311a6408SLad Prabhakar 	 * configure parallel port control lines polarity
2490311a6408SLad Prabhakar 	 *
2491311a6408SLad Prabhakar 	 * POLARITY CTRL0
2492311a6408SLad Prabhakar 	 * - [5]:	PCLK polarity (0: active low, 1: active high)
2493311a6408SLad Prabhakar 	 * - [1]:	HREF polarity (0: active low, 1: active high)
2494311a6408SLad Prabhakar 	 * - [0]:	VSYNC polarity (mismatch here between
2495311a6408SLad Prabhakar 	 *		datasheet and hardware, 0 is active high
2496311a6408SLad Prabhakar 	 *		and 1 is active low...)
2497311a6408SLad Prabhakar 	 */
249868579b32SHugues Fruchet 	if (!bt656) {
2499311a6408SLad Prabhakar 		if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
250068579b32SHugues Fruchet 			polarities |= BIT(1);
2501311a6408SLad Prabhakar 		if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
250268579b32SHugues Fruchet 			polarities |= BIT(0);
250368579b32SHugues Fruchet 	}
250468579b32SHugues Fruchet 	if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
250568579b32SHugues Fruchet 		polarities |= BIT(5);
2506311a6408SLad Prabhakar 
250768579b32SHugues Fruchet 	ret = ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, polarities);
2508311a6408SLad Prabhakar 	if (ret)
2509311a6408SLad Prabhakar 		return ret;
2510311a6408SLad Prabhakar 
2511311a6408SLad Prabhakar 	/*
251268579b32SHugues Fruchet 	 * powerdown MIPI TX/RX PHY & enable DVP
2513311a6408SLad Prabhakar 	 *
2514311a6408SLad Prabhakar 	 * MIPI CONTROL 00
251568579b32SHugues Fruchet 	 * [4] = 1	: Power down MIPI HS Tx
251668579b32SHugues Fruchet 	 * [3] = 1	: Power down MIPI LS Rx
251768579b32SHugues Fruchet 	 * [2] = 0	: DVP enable (MIPI disable)
2518311a6408SLad Prabhakar 	 */
2519311a6408SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x18);
2520311a6408SLad Prabhakar 	if (ret)
2521311a6408SLad Prabhakar 		return ret;
2522311a6408SLad Prabhakar 
2523311a6408SLad Prabhakar 	/*
2524576f5d4bSLad Prabhakar 	 * enable VSYNC/HREF/PCLK DVP control lines
2525576f5d4bSLad Prabhakar 	 * & D[9:6] DVP data lines
2526576f5d4bSLad Prabhakar 	 *
2527576f5d4bSLad Prabhakar 	 * PAD OUTPUT ENABLE 01
2528576f5d4bSLad Prabhakar 	 * - 6:		VSYNC output enable
2529576f5d4bSLad Prabhakar 	 * - 5:		HREF output enable
2530576f5d4bSLad Prabhakar 	 * - 4:		PCLK output enable
2531576f5d4bSLad Prabhakar 	 * - [3:0]:	D[9:6] output enable
2532576f5d4bSLad Prabhakar 	 */
25334039b037SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01,
253468579b32SHugues Fruchet 			       bt656 ? 0x1f : 0x7f);
2535576f5d4bSLad Prabhakar 	if (ret)
2536576f5d4bSLad Prabhakar 		return ret;
2537576f5d4bSLad Prabhakar 
2538576f5d4bSLad Prabhakar 	/*
2539576f5d4bSLad Prabhakar 	 * enable D[5:0] DVP data lines
2540576f5d4bSLad Prabhakar 	 *
2541576f5d4bSLad Prabhakar 	 * PAD OUTPUT ENABLE 02
2542576f5d4bSLad Prabhakar 	 * - [7:2]:	D[5:0] output enable
2543576f5d4bSLad Prabhakar 	 */
2544576f5d4bSLad Prabhakar 	return ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0xfc);
2545576f5d4bSLad Prabhakar }
2546576f5d4bSLad Prabhakar 
25470f7acb52SHugues Fruchet static int ov5640_set_power(struct ov5640_dev *sensor, bool on)
25480f7acb52SHugues Fruchet {
25490f7acb52SHugues Fruchet 	int ret = 0;
25500f7acb52SHugues Fruchet 
25510f7acb52SHugues Fruchet 	if (on) {
25520f7acb52SHugues Fruchet 		ret = ov5640_set_power_on(sensor);
25530f7acb52SHugues Fruchet 		if (ret)
25540f7acb52SHugues Fruchet 			return ret;
25550f7acb52SHugues Fruchet 
255619a81c14SSteve Longerbeam 		ret = ov5640_restore_mode(sensor);
255719a81c14SSteve Longerbeam 		if (ret)
255819a81c14SSteve Longerbeam 			goto power_off;
2559b1751ae6SLad Prabhakar 	}
256019a81c14SSteve Longerbeam 
2561576f5d4bSLad Prabhakar 	if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY)
2562b1751ae6SLad Prabhakar 		ret = ov5640_set_power_mipi(sensor, on);
2563576f5d4bSLad Prabhakar 	else
2564576f5d4bSLad Prabhakar 		ret = ov5640_set_power_dvp(sensor, on);
2565b1751ae6SLad Prabhakar 	if (ret)
2566b1751ae6SLad Prabhakar 		goto power_off;
2567aa4bb8b8SJacopo Mondi 
2568b1751ae6SLad Prabhakar 	if (!on)
2569aa4bb8b8SJacopo Mondi 		ov5640_set_power_off(sensor);
257019a81c14SSteve Longerbeam 
257119a81c14SSteve Longerbeam 	return 0;
257219a81c14SSteve Longerbeam 
257319a81c14SSteve Longerbeam power_off:
25740f7acb52SHugues Fruchet 	ov5640_set_power_off(sensor);
257519a81c14SSteve Longerbeam 	return ret;
257619a81c14SSteve Longerbeam }
257719a81c14SSteve Longerbeam 
257819a81c14SSteve Longerbeam /* --------------- Subdev Operations --------------- */
257919a81c14SSteve Longerbeam 
258019a81c14SSteve Longerbeam static int ov5640_s_power(struct v4l2_subdev *sd, int on)
258119a81c14SSteve Longerbeam {
258219a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
258319a81c14SSteve Longerbeam 	int ret = 0;
258419a81c14SSteve Longerbeam 
258519a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
258619a81c14SSteve Longerbeam 
258719a81c14SSteve Longerbeam 	/*
258819a81c14SSteve Longerbeam 	 * If the power count is modified from 0 to != 0 or from != 0 to 0,
258919a81c14SSteve Longerbeam 	 * update the power state.
259019a81c14SSteve Longerbeam 	 */
259119a81c14SSteve Longerbeam 	if (sensor->power_count == !on) {
259219a81c14SSteve Longerbeam 		ret = ov5640_set_power(sensor, !!on);
259319a81c14SSteve Longerbeam 		if (ret)
259419a81c14SSteve Longerbeam 			goto out;
259519a81c14SSteve Longerbeam 	}
259619a81c14SSteve Longerbeam 
259719a81c14SSteve Longerbeam 	/* Update the power count. */
259819a81c14SSteve Longerbeam 	sensor->power_count += on ? 1 : -1;
259919a81c14SSteve Longerbeam 	WARN_ON(sensor->power_count < 0);
260019a81c14SSteve Longerbeam out:
260119a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
260219a81c14SSteve Longerbeam 
260319a81c14SSteve Longerbeam 	if (on && !ret && sensor->power_count == 1) {
260419a81c14SSteve Longerbeam 		/* restore controls */
260519a81c14SSteve Longerbeam 		ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
260619a81c14SSteve Longerbeam 	}
260719a81c14SSteve Longerbeam 
260819a81c14SSteve Longerbeam 	return ret;
260919a81c14SSteve Longerbeam }
261019a81c14SSteve Longerbeam 
261119a81c14SSteve Longerbeam static int ov5640_try_frame_interval(struct ov5640_dev *sensor,
261219a81c14SSteve Longerbeam 				     struct v4l2_fract *fi,
261319a81c14SSteve Longerbeam 				     u32 width, u32 height)
261419a81c14SSteve Longerbeam {
261519a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
26166530a5ebSJagan Teki 	enum ov5640_frame_rate rate = OV5640_15_FPS;
2617f6cc192fSMaxime Ripard 	int minfps, maxfps, best_fps, fps;
2618f6cc192fSMaxime Ripard 	int i;
261919a81c14SSteve Longerbeam 
262019a81c14SSteve Longerbeam 	minfps = ov5640_framerates[OV5640_15_FPS];
2621e823fb16SMaxime Ripard 	maxfps = ov5640_framerates[OV5640_60_FPS];
262219a81c14SSteve Longerbeam 
262319a81c14SSteve Longerbeam 	if (fi->numerator == 0) {
262419a81c14SSteve Longerbeam 		fi->denominator = maxfps;
262519a81c14SSteve Longerbeam 		fi->numerator = 1;
2626e823fb16SMaxime Ripard 		rate = OV5640_60_FPS;
2627e823fb16SMaxime Ripard 		goto find_mode;
262819a81c14SSteve Longerbeam 	}
262919a81c14SSteve Longerbeam 
2630f6cc192fSMaxime Ripard 	fps = clamp_val(DIV_ROUND_CLOSEST(fi->denominator, fi->numerator),
2631f6cc192fSMaxime Ripard 			minfps, maxfps);
2632f6cc192fSMaxime Ripard 
2633f6cc192fSMaxime Ripard 	best_fps = minfps;
2634f6cc192fSMaxime Ripard 	for (i = 0; i < ARRAY_SIZE(ov5640_framerates); i++) {
2635f6cc192fSMaxime Ripard 		int curr_fps = ov5640_framerates[i];
2636f6cc192fSMaxime Ripard 
2637f6cc192fSMaxime Ripard 		if (abs(curr_fps - fps) < abs(best_fps - fps)) {
2638f6cc192fSMaxime Ripard 			best_fps = curr_fps;
2639f6cc192fSMaxime Ripard 			rate = i;
2640f6cc192fSMaxime Ripard 		}
2641f6cc192fSMaxime Ripard 	}
264219a81c14SSteve Longerbeam 
264319a81c14SSteve Longerbeam 	fi->numerator = 1;
2644f6cc192fSMaxime Ripard 	fi->denominator = best_fps;
264519a81c14SSteve Longerbeam 
2646e823fb16SMaxime Ripard find_mode:
2647*b6ae5022SJacopo Mondi 	mode = ov5640_find_mode(sensor, width, height, false);
26485a3ad937SMaxime Ripard 	return mode ? rate : -EINVAL;
264919a81c14SSteve Longerbeam }
265019a81c14SSteve Longerbeam 
265119a81c14SSteve Longerbeam static int ov5640_get_fmt(struct v4l2_subdev *sd,
26520d346d2aSTomi Valkeinen 			  struct v4l2_subdev_state *sd_state,
265319a81c14SSteve Longerbeam 			  struct v4l2_subdev_format *format)
265419a81c14SSteve Longerbeam {
265519a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
265619a81c14SSteve Longerbeam 	struct v4l2_mbus_framefmt *fmt;
265719a81c14SSteve Longerbeam 
265819a81c14SSteve Longerbeam 	if (format->pad != 0)
265919a81c14SSteve Longerbeam 		return -EINVAL;
266019a81c14SSteve Longerbeam 
266119a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
266219a81c14SSteve Longerbeam 
266319a81c14SSteve Longerbeam 	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
26640d346d2aSTomi Valkeinen 		fmt = v4l2_subdev_get_try_format(&sensor->sd, sd_state,
266519a81c14SSteve Longerbeam 						 format->pad);
266619a81c14SSteve Longerbeam 	else
266719a81c14SSteve Longerbeam 		fmt = &sensor->fmt;
266819a81c14SSteve Longerbeam 
266919a81c14SSteve Longerbeam 	format->format = *fmt;
267019a81c14SSteve Longerbeam 
267119a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
267219a81c14SSteve Longerbeam 
267319a81c14SSteve Longerbeam 	return 0;
267419a81c14SSteve Longerbeam }
267519a81c14SSteve Longerbeam 
267619a81c14SSteve Longerbeam static int ov5640_try_fmt_internal(struct v4l2_subdev *sd,
267719a81c14SSteve Longerbeam 				   struct v4l2_mbus_framefmt *fmt,
267819a81c14SSteve Longerbeam 				   enum ov5640_frame_rate fr,
267919a81c14SSteve Longerbeam 				   const struct ov5640_mode_info **new_mode)
268019a81c14SSteve Longerbeam {
268119a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
268219a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
2683e3ee691dSHugues Fruchet 	int i;
268419a81c14SSteve Longerbeam 
2685*b6ae5022SJacopo Mondi 	mode = ov5640_find_mode(sensor, fmt->width, fmt->height, true);
268619a81c14SSteve Longerbeam 	if (!mode)
268719a81c14SSteve Longerbeam 		return -EINVAL;
26885113d5b3SJacopo Mondi 	fmt->width = mode->width;
26895113d5b3SJacopo Mondi 	fmt->height = mode->height;
269019a81c14SSteve Longerbeam 
269119a81c14SSteve Longerbeam 	if (new_mode)
269219a81c14SSteve Longerbeam 		*new_mode = mode;
2693e3ee691dSHugues Fruchet 
2694e3ee691dSHugues Fruchet 	for (i = 0; i < ARRAY_SIZE(ov5640_formats); i++)
2695e3ee691dSHugues Fruchet 		if (ov5640_formats[i].code == fmt->code)
2696e3ee691dSHugues Fruchet 			break;
2697e3ee691dSHugues Fruchet 	if (i >= ARRAY_SIZE(ov5640_formats))
2698e6441fdeSHugues Fruchet 		i = 0;
2699e6441fdeSHugues Fruchet 
2700e6441fdeSHugues Fruchet 	fmt->code = ov5640_formats[i].code;
2701e6441fdeSHugues Fruchet 	fmt->colorspace = ov5640_formats[i].colorspace;
2702e6441fdeSHugues Fruchet 	fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
2703e6441fdeSHugues Fruchet 	fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
2704e6441fdeSHugues Fruchet 	fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
2705e3ee691dSHugues Fruchet 
270619a81c14SSteve Longerbeam 	return 0;
270719a81c14SSteve Longerbeam }
270819a81c14SSteve Longerbeam 
27093c28588fSJacopo Mondi static int ov5640_update_pixel_rate(struct ov5640_dev *sensor)
27103c28588fSJacopo Mondi {
27113c28588fSJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
27123c28588fSJacopo Mondi 	enum ov5640_pixel_rate_id pixel_rate_id = mode->pixel_rate;
27133c28588fSJacopo Mondi 	struct v4l2_mbus_framefmt *fmt = &sensor->fmt;
271432979f67SJacopo Mondi 	const struct ov5640_timings *timings;
2715bce93b82SJacopo Mondi 	s32 exposure_val, exposure_max;
271632979f67SJacopo Mondi 	unsigned int hblank;
27173c28588fSJacopo Mondi 	unsigned int i = 0;
27183c28588fSJacopo Mondi 	u32 pixel_rate;
27193c28588fSJacopo Mondi 	s64 link_freq;
27203c28588fSJacopo Mondi 	u32 num_lanes;
272119f2e3e6SHugues Fruchet 	u32 vblank;
27223c28588fSJacopo Mondi 	u32 bpp;
27233c28588fSJacopo Mondi 
27243c28588fSJacopo Mondi 	/*
27253c28588fSJacopo Mondi 	 * Update the pixel rate control value.
27263c28588fSJacopo Mondi 	 *
27273c28588fSJacopo Mondi 	 * For DVP mode, maintain the pixel rate calculation using fixed FPS.
27283c28588fSJacopo Mondi 	 */
27293c28588fSJacopo Mondi 	if (!ov5640_is_csi2(sensor)) {
27303c28588fSJacopo Mondi 		__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate,
27313c28588fSJacopo Mondi 					 ov5640_calc_pixel_rate(sensor));
27323c28588fSJacopo Mondi 
27333c28588fSJacopo Mondi 		return 0;
27343c28588fSJacopo Mondi 	}
27353c28588fSJacopo Mondi 
27363c28588fSJacopo Mondi 	/*
27373c28588fSJacopo Mondi 	 * The MIPI CSI-2 link frequency should comply with the CSI-2
27383c28588fSJacopo Mondi 	 * specification and be lower than 1GHz.
27393c28588fSJacopo Mondi 	 *
27403c28588fSJacopo Mondi 	 * Start from the suggested pixel_rate for the current mode and
27413c28588fSJacopo Mondi 	 * progressively slow it down if it exceeds 1GHz.
27423c28588fSJacopo Mondi 	 */
27433c28588fSJacopo Mondi 	num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes;
27443c28588fSJacopo Mondi 	bpp = ov5640_code_to_bpp(fmt->code);
27453c28588fSJacopo Mondi 	do {
27463c28588fSJacopo Mondi 		pixel_rate = ov5640_pixel_rates[pixel_rate_id];
27473c28588fSJacopo Mondi 		link_freq = pixel_rate * bpp / (2 * num_lanes);
27483c28588fSJacopo Mondi 	} while (link_freq >= 1000000000U &&
27493c28588fSJacopo Mondi 		 ++pixel_rate_id < OV5640_NUM_PIXEL_RATES);
27503c28588fSJacopo Mondi 
27513c28588fSJacopo Mondi 	sensor->current_link_freq = link_freq;
27523c28588fSJacopo Mondi 
27533c28588fSJacopo Mondi 	/*
27543c28588fSJacopo Mondi 	 * Higher link rates require the clock tree to be programmed with
27553c28588fSJacopo Mondi 	 * 'mipi_div' = 1; this has the effect of halving the actual output
27563c28588fSJacopo Mondi 	 * pixel rate in the MIPI domain.
27573c28588fSJacopo Mondi 	 *
27583c28588fSJacopo Mondi 	 * Adjust the pixel rate and link frequency control value to report it
27593c28588fSJacopo Mondi 	 * correctly to userspace.
27603c28588fSJacopo Mondi 	 */
27613c28588fSJacopo Mondi 	if (link_freq > OV5640_LINK_RATE_MAX) {
27623c28588fSJacopo Mondi 		pixel_rate /= 2;
27633c28588fSJacopo Mondi 		link_freq /= 2;
27643c28588fSJacopo Mondi 	}
27653c28588fSJacopo Mondi 
27663c28588fSJacopo Mondi 	for (i = 0; i < ARRAY_SIZE(ov5640_csi2_link_freqs); ++i) {
27673c28588fSJacopo Mondi 		if (ov5640_csi2_link_freqs[i] == link_freq)
27683c28588fSJacopo Mondi 			break;
27693c28588fSJacopo Mondi 	}
27703c28588fSJacopo Mondi 	WARN_ON(i == ARRAY_SIZE(ov5640_csi2_link_freqs));
27713c28588fSJacopo Mondi 
27723c28588fSJacopo Mondi 	__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, pixel_rate);
27733c28588fSJacopo Mondi 	__v4l2_ctrl_s_ctrl(sensor->ctrls.link_freq, i);
27743c28588fSJacopo Mondi 
277532979f67SJacopo Mondi 	timings = ov5640_timings(sensor, mode);
277632979f67SJacopo Mondi 	hblank = timings->htot - mode->width;
277732979f67SJacopo Mondi 	__v4l2_ctrl_modify_range(sensor->ctrls.hblank,
277832979f67SJacopo Mondi 				 hblank, hblank, 1, hblank);
277932979f67SJacopo Mondi 
278019f2e3e6SHugues Fruchet 	vblank = timings->vblank_def;
2781bce93b82SJacopo Mondi 
278219f2e3e6SHugues Fruchet 	if (sensor->current_fr != mode->def_fps) {
278319f2e3e6SHugues Fruchet 		/*
278419f2e3e6SHugues Fruchet 		 * Compute the vertical blanking according to the framerate
278519f2e3e6SHugues Fruchet 		 * configured with s_frame_interval.
278619f2e3e6SHugues Fruchet 		 */
278719f2e3e6SHugues Fruchet 		int fie_num = sensor->frame_interval.numerator;
278819f2e3e6SHugues Fruchet 		int fie_denom = sensor->frame_interval.denominator;
278919f2e3e6SHugues Fruchet 
279019f2e3e6SHugues Fruchet 		vblank = ((fie_num * pixel_rate / fie_denom) / timings->htot) -
279119f2e3e6SHugues Fruchet 			mode->height;
279219f2e3e6SHugues Fruchet 	}
279319f2e3e6SHugues Fruchet 
279419f2e3e6SHugues Fruchet 	__v4l2_ctrl_modify_range(sensor->ctrls.vblank, OV5640_MIN_VBLANK,
279519f2e3e6SHugues Fruchet 				 OV5640_MAX_VTS - mode->height, 1, vblank);
279619f2e3e6SHugues Fruchet 	__v4l2_ctrl_s_ctrl(sensor->ctrls.vblank, vblank);
279719f2e3e6SHugues Fruchet 
279819f2e3e6SHugues Fruchet 	exposure_max = timings->crop.height + vblank - 4;
2799bce93b82SJacopo Mondi 	exposure_val = clamp_t(s32, sensor->ctrls.exposure->val,
2800bce93b82SJacopo Mondi 			       sensor->ctrls.exposure->minimum,
2801bce93b82SJacopo Mondi 			       exposure_max);
280219f2e3e6SHugues Fruchet 
2803bce93b82SJacopo Mondi 	__v4l2_ctrl_modify_range(sensor->ctrls.exposure,
2804bce93b82SJacopo Mondi 				 sensor->ctrls.exposure->minimum,
2805bce93b82SJacopo Mondi 				 exposure_max, 1, exposure_val);
2806bce93b82SJacopo Mondi 
28073c28588fSJacopo Mondi 	return 0;
28083c28588fSJacopo Mondi }
28093c28588fSJacopo Mondi 
281019a81c14SSteve Longerbeam static int ov5640_set_fmt(struct v4l2_subdev *sd,
28110d346d2aSTomi Valkeinen 			  struct v4l2_subdev_state *sd_state,
281219a81c14SSteve Longerbeam 			  struct v4l2_subdev_format *format)
281319a81c14SSteve Longerbeam {
281419a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
281519a81c14SSteve Longerbeam 	const struct ov5640_mode_info *new_mode;
2816e6441fdeSHugues Fruchet 	struct v4l2_mbus_framefmt *mbus_fmt = &format->format;
281719a81c14SSteve Longerbeam 	int ret;
281819a81c14SSteve Longerbeam 
281919a81c14SSteve Longerbeam 	if (format->pad != 0)
282019a81c14SSteve Longerbeam 		return -EINVAL;
282119a81c14SSteve Longerbeam 
282219a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
282319a81c14SSteve Longerbeam 
282419a81c14SSteve Longerbeam 	if (sensor->streaming) {
282519a81c14SSteve Longerbeam 		ret = -EBUSY;
282619a81c14SSteve Longerbeam 		goto out;
282719a81c14SSteve Longerbeam 	}
282819a81c14SSteve Longerbeam 
2829e6441fdeSHugues Fruchet 	ret = ov5640_try_fmt_internal(sd, mbus_fmt,
283019a81c14SSteve Longerbeam 				      sensor->current_fr, &new_mode);
283119a81c14SSteve Longerbeam 	if (ret)
283219a81c14SSteve Longerbeam 		goto out;
283319a81c14SSteve Longerbeam 
2834e738f5ddSMirela Rabulea 	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
2835e738f5ddSMirela Rabulea 		*v4l2_subdev_get_try_format(sd, sd_state, 0) = *mbus_fmt;
2836e738f5ddSMirela Rabulea 		goto out;
2837e738f5ddSMirela Rabulea 	}
283819a81c14SSteve Longerbeam 
28396949d864SHugues Fruchet 	if (new_mode != sensor->current_mode) {
284019f2e3e6SHugues Fruchet 		sensor->current_fr = new_mode->def_fps;
284119a81c14SSteve Longerbeam 		sensor->current_mode = new_mode;
284219a81c14SSteve Longerbeam 		sensor->pending_mode_change = true;
28436949d864SHugues Fruchet 	}
284407115449SJacopo Mondi 	if (mbus_fmt->code != sensor->fmt.code)
2845fb98e29fSHugues Fruchet 		sensor->pending_fmt_change = true;
284607115449SJacopo Mondi 
2847e738f5ddSMirela Rabulea 	/* update format even if code is unchanged, resolution might change */
2848e738f5ddSMirela Rabulea 	sensor->fmt = *mbus_fmt;
2849e738f5ddSMirela Rabulea 
28503c28588fSJacopo Mondi 	ov5640_update_pixel_rate(sensor);
28513c28588fSJacopo Mondi 
285219a81c14SSteve Longerbeam out:
285319a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
285419a81c14SSteve Longerbeam 	return ret;
285519a81c14SSteve Longerbeam }
285619a81c14SSteve Longerbeam 
2857e3ee691dSHugues Fruchet static int ov5640_set_framefmt(struct ov5640_dev *sensor,
2858e3ee691dSHugues Fruchet 			       struct v4l2_mbus_framefmt *format)
2859e3ee691dSHugues Fruchet {
2860e3ee691dSHugues Fruchet 	int ret = 0;
2861d47c4126SHugues Fruchet 	bool is_jpeg = false;
2862b7ed3abdSLoic Poulain 	u8 fmt, mux;
2863e3ee691dSHugues Fruchet 
2864e3ee691dSHugues Fruchet 	switch (format->code) {
28651536fbdbSXavier Roumegue 	case MEDIA_BUS_FMT_UYVY8_1X16:
2866e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_UYVY8_2X8:
2867e3ee691dSHugues Fruchet 		/* YUV422, UYVY */
2868b7ed3abdSLoic Poulain 		fmt = 0x3f;
2869b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_YUV422;
2870e3ee691dSHugues Fruchet 		break;
28711536fbdbSXavier Roumegue 	case MEDIA_BUS_FMT_YUYV8_1X16:
2872e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_YUYV8_2X8:
2873e3ee691dSHugues Fruchet 		/* YUV422, YUYV */
2874b7ed3abdSLoic Poulain 		fmt = 0x30;
2875b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_YUV422;
2876e3ee691dSHugues Fruchet 		break;
2877e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_RGB565_2X8_LE:
2878e3ee691dSHugues Fruchet 		/* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */
2879b7ed3abdSLoic Poulain 		fmt = 0x6F;
2880b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RGB;
2881e3ee691dSHugues Fruchet 		break;
2882e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_RGB565_2X8_BE:
2883e3ee691dSHugues Fruchet 		/* RGB565 {r[4:0],g[5:3]},{g[2:0],b[4:0]} */
2884b7ed3abdSLoic Poulain 		fmt = 0x61;
2885b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RGB;
2886e3ee691dSHugues Fruchet 		break;
2887d47c4126SHugues Fruchet 	case MEDIA_BUS_FMT_JPEG_1X8:
2888d47c4126SHugues Fruchet 		/* YUV422, YUYV */
2889b7ed3abdSLoic Poulain 		fmt = 0x30;
2890b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_YUV422;
2891d47c4126SHugues Fruchet 		is_jpeg = true;
2892d47c4126SHugues Fruchet 		break;
2893b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SBGGR8_1X8:
2894b7ed3abdSLoic Poulain 		/* Raw, BGBG... / GRGR... */
2895b7ed3abdSLoic Poulain 		fmt = 0x00;
2896b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2897b7ed3abdSLoic Poulain 		break;
2898b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SGBRG8_1X8:
2899b7ed3abdSLoic Poulain 		/* Raw bayer, GBGB... / RGRG... */
2900b7ed3abdSLoic Poulain 		fmt = 0x01;
2901b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2902b7ed3abdSLoic Poulain 		break;
2903b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SGRBG8_1X8:
2904b7ed3abdSLoic Poulain 		/* Raw bayer, GRGR... / BGBG... */
2905b7ed3abdSLoic Poulain 		fmt = 0x02;
2906b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2907b7ed3abdSLoic Poulain 		break;
2908b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SRGGB8_1X8:
2909b7ed3abdSLoic Poulain 		/* Raw bayer, RGRG... / GBGB... */
2910b7ed3abdSLoic Poulain 		fmt = 0x03;
2911b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2912b7ed3abdSLoic Poulain 		break;
2913e3ee691dSHugues Fruchet 	default:
2914e3ee691dSHugues Fruchet 		return -EINVAL;
2915e3ee691dSHugues Fruchet 	}
2916e3ee691dSHugues Fruchet 
2917e3ee691dSHugues Fruchet 	/* FORMAT CONTROL00: YUV and RGB formatting */
2918b7ed3abdSLoic Poulain 	ret = ov5640_write_reg(sensor, OV5640_REG_FORMAT_CONTROL00, fmt);
2919e3ee691dSHugues Fruchet 	if (ret)
2920e3ee691dSHugues Fruchet 		return ret;
2921e3ee691dSHugues Fruchet 
2922e3ee691dSHugues Fruchet 	/* FORMAT MUX CONTROL: ISP YUV or RGB */
2923b7ed3abdSLoic Poulain 	ret = ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL, mux);
2924d47c4126SHugues Fruchet 	if (ret)
2925d47c4126SHugues Fruchet 		return ret;
2926d47c4126SHugues Fruchet 
2927d47c4126SHugues Fruchet 	/*
2928d47c4126SHugues Fruchet 	 * TIMING TC REG21:
2929d47c4126SHugues Fruchet 	 * - [5]:	JPEG enable
2930d47c4126SHugues Fruchet 	 */
2931d47c4126SHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
2932d47c4126SHugues Fruchet 			     BIT(5), is_jpeg ? BIT(5) : 0);
2933d47c4126SHugues Fruchet 	if (ret)
2934d47c4126SHugues Fruchet 		return ret;
2935d47c4126SHugues Fruchet 
2936d47c4126SHugues Fruchet 	/*
2937d47c4126SHugues Fruchet 	 * SYSTEM RESET02:
2938d47c4126SHugues Fruchet 	 * - [4]:	Reset JFIFO
2939d47c4126SHugues Fruchet 	 * - [3]:	Reset SFIFO
2940d47c4126SHugues Fruchet 	 * - [2]:	Reset JPEG
2941d47c4126SHugues Fruchet 	 */
2942d47c4126SHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_RESET02,
2943d47c4126SHugues Fruchet 			     BIT(4) | BIT(3) | BIT(2),
2944d47c4126SHugues Fruchet 			     is_jpeg ? 0 : (BIT(4) | BIT(3) | BIT(2)));
2945d47c4126SHugues Fruchet 	if (ret)
2946d47c4126SHugues Fruchet 		return ret;
2947d47c4126SHugues Fruchet 
2948d47c4126SHugues Fruchet 	/*
2949d47c4126SHugues Fruchet 	 * CLOCK ENABLE02:
2950d47c4126SHugues Fruchet 	 * - [5]:	Enable JPEG 2x clock
2951d47c4126SHugues Fruchet 	 * - [3]:	Enable JPEG clock
2952d47c4126SHugues Fruchet 	 */
2953d47c4126SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_SYS_CLOCK_ENABLE02,
2954d47c4126SHugues Fruchet 			      BIT(5) | BIT(3),
2955d47c4126SHugues Fruchet 			      is_jpeg ? (BIT(5) | BIT(3)) : 0);
2956e3ee691dSHugues Fruchet }
295719a81c14SSteve Longerbeam 
295819a81c14SSteve Longerbeam /*
295919a81c14SSteve Longerbeam  * Sensor Controls.
296019a81c14SSteve Longerbeam  */
296119a81c14SSteve Longerbeam 
296219a81c14SSteve Longerbeam static int ov5640_set_ctrl_hue(struct ov5640_dev *sensor, int value)
296319a81c14SSteve Longerbeam {
296419a81c14SSteve Longerbeam 	int ret;
296519a81c14SSteve Longerbeam 
296619a81c14SSteve Longerbeam 	if (value) {
296719a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
296819a81c14SSteve Longerbeam 				     BIT(0), BIT(0));
296919a81c14SSteve Longerbeam 		if (ret)
297019a81c14SSteve Longerbeam 			return ret;
297119a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_SDE_CTRL1, value);
297219a81c14SSteve Longerbeam 	} else {
297319a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(0), 0);
297419a81c14SSteve Longerbeam 	}
297519a81c14SSteve Longerbeam 
297619a81c14SSteve Longerbeam 	return ret;
297719a81c14SSteve Longerbeam }
297819a81c14SSteve Longerbeam 
297919a81c14SSteve Longerbeam static int ov5640_set_ctrl_contrast(struct ov5640_dev *sensor, int value)
298019a81c14SSteve Longerbeam {
298119a81c14SSteve Longerbeam 	int ret;
298219a81c14SSteve Longerbeam 
298319a81c14SSteve Longerbeam 	if (value) {
298419a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
298519a81c14SSteve Longerbeam 				     BIT(2), BIT(2));
298619a81c14SSteve Longerbeam 		if (ret)
298719a81c14SSteve Longerbeam 			return ret;
298819a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL5,
298919a81c14SSteve Longerbeam 				       value & 0xff);
299019a81c14SSteve Longerbeam 	} else {
299119a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(2), 0);
299219a81c14SSteve Longerbeam 	}
299319a81c14SSteve Longerbeam 
299419a81c14SSteve Longerbeam 	return ret;
299519a81c14SSteve Longerbeam }
299619a81c14SSteve Longerbeam 
299719a81c14SSteve Longerbeam static int ov5640_set_ctrl_saturation(struct ov5640_dev *sensor, int value)
299819a81c14SSteve Longerbeam {
299919a81c14SSteve Longerbeam 	int ret;
300019a81c14SSteve Longerbeam 
300119a81c14SSteve Longerbeam 	if (value) {
300219a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
300319a81c14SSteve Longerbeam 				     BIT(1), BIT(1));
300419a81c14SSteve Longerbeam 		if (ret)
300519a81c14SSteve Longerbeam 			return ret;
300619a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL3,
300719a81c14SSteve Longerbeam 				       value & 0xff);
300819a81c14SSteve Longerbeam 		if (ret)
300919a81c14SSteve Longerbeam 			return ret;
301019a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL4,
301119a81c14SSteve Longerbeam 				       value & 0xff);
301219a81c14SSteve Longerbeam 	} else {
301319a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(1), 0);
301419a81c14SSteve Longerbeam 	}
301519a81c14SSteve Longerbeam 
301619a81c14SSteve Longerbeam 	return ret;
301719a81c14SSteve Longerbeam }
301819a81c14SSteve Longerbeam 
301919a81c14SSteve Longerbeam static int ov5640_set_ctrl_white_balance(struct ov5640_dev *sensor, int awb)
302019a81c14SSteve Longerbeam {
302119a81c14SSteve Longerbeam 	int ret;
302219a81c14SSteve Longerbeam 
302319a81c14SSteve Longerbeam 	ret = ov5640_mod_reg(sensor, OV5640_REG_AWB_MANUAL_CTRL,
302419a81c14SSteve Longerbeam 			     BIT(0), awb ? 0 : 1);
302519a81c14SSteve Longerbeam 	if (ret)
302619a81c14SSteve Longerbeam 		return ret;
302719a81c14SSteve Longerbeam 
302819a81c14SSteve Longerbeam 	if (!awb) {
302919a81c14SSteve Longerbeam 		u16 red = (u16)sensor->ctrls.red_balance->val;
303019a81c14SSteve Longerbeam 		u16 blue = (u16)sensor->ctrls.blue_balance->val;
303119a81c14SSteve Longerbeam 
303219a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_R_GAIN, red);
303319a81c14SSteve Longerbeam 		if (ret)
303419a81c14SSteve Longerbeam 			return ret;
303519a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_B_GAIN, blue);
303619a81c14SSteve Longerbeam 	}
303719a81c14SSteve Longerbeam 
303819a81c14SSteve Longerbeam 	return ret;
303919a81c14SSteve Longerbeam }
304019a81c14SSteve Longerbeam 
30413cca8ef5SHugues Fruchet static int ov5640_set_ctrl_exposure(struct ov5640_dev *sensor,
30423cca8ef5SHugues Fruchet 				    enum v4l2_exposure_auto_type auto_exposure)
304319a81c14SSteve Longerbeam {
304419a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
30453cca8ef5SHugues Fruchet 	bool auto_exp = (auto_exposure == V4L2_EXPOSURE_AUTO);
304619a81c14SSteve Longerbeam 	int ret = 0;
304719a81c14SSteve Longerbeam 
304819a81c14SSteve Longerbeam 	if (ctrls->auto_exp->is_new) {
30493cca8ef5SHugues Fruchet 		ret = ov5640_set_autoexposure(sensor, auto_exp);
305019a81c14SSteve Longerbeam 		if (ret)
305119a81c14SSteve Longerbeam 			return ret;
305219a81c14SSteve Longerbeam 	}
305319a81c14SSteve Longerbeam 
30543cca8ef5SHugues Fruchet 	if (!auto_exp && ctrls->exposure->is_new) {
305519a81c14SSteve Longerbeam 		u16 max_exp;
305619a81c14SSteve Longerbeam 
305719a81c14SSteve Longerbeam 		ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_VTS,
305819a81c14SSteve Longerbeam 					&max_exp);
305919a81c14SSteve Longerbeam 		if (ret)
306019a81c14SSteve Longerbeam 			return ret;
306119a81c14SSteve Longerbeam 		ret = ov5640_get_vts(sensor);
306219a81c14SSteve Longerbeam 		if (ret < 0)
306319a81c14SSteve Longerbeam 			return ret;
306419a81c14SSteve Longerbeam 		max_exp += ret;
30656146fde3SHugues Fruchet 		ret = 0;
306619a81c14SSteve Longerbeam 
306719a81c14SSteve Longerbeam 		if (ctrls->exposure->val < max_exp)
306819a81c14SSteve Longerbeam 			ret = ov5640_set_exposure(sensor, ctrls->exposure->val);
306919a81c14SSteve Longerbeam 	}
307019a81c14SSteve Longerbeam 
307119a81c14SSteve Longerbeam 	return ret;
307219a81c14SSteve Longerbeam }
307319a81c14SSteve Longerbeam 
30743cca8ef5SHugues Fruchet static int ov5640_set_ctrl_gain(struct ov5640_dev *sensor, bool auto_gain)
307519a81c14SSteve Longerbeam {
307619a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
307719a81c14SSteve Longerbeam 	int ret = 0;
307819a81c14SSteve Longerbeam 
307919a81c14SSteve Longerbeam 	if (ctrls->auto_gain->is_new) {
30803cca8ef5SHugues Fruchet 		ret = ov5640_set_autogain(sensor, auto_gain);
308119a81c14SSteve Longerbeam 		if (ret)
308219a81c14SSteve Longerbeam 			return ret;
308319a81c14SSteve Longerbeam 	}
308419a81c14SSteve Longerbeam 
30853cca8ef5SHugues Fruchet 	if (!auto_gain && ctrls->gain->is_new)
30863cca8ef5SHugues Fruchet 		ret = ov5640_set_gain(sensor, ctrls->gain->val);
308719a81c14SSteve Longerbeam 
308819a81c14SSteve Longerbeam 	return ret;
308919a81c14SSteve Longerbeam }
309019a81c14SSteve Longerbeam 
30919f6d7bacSChen-Yu Tsai static const char * const test_pattern_menu[] = {
30929f6d7bacSChen-Yu Tsai 	"Disabled",
30939f6d7bacSChen-Yu Tsai 	"Color bars",
3094bddc5cdfSChen-Yu Tsai 	"Color bars w/ rolling bar",
3095bddc5cdfSChen-Yu Tsai 	"Color squares",
3096bddc5cdfSChen-Yu Tsai 	"Color squares w/ rolling bar",
30979f6d7bacSChen-Yu Tsai };
30989f6d7bacSChen-Yu Tsai 
3099a0c29afbSChen-Yu Tsai #define OV5640_TEST_ENABLE		BIT(7)
3100a0c29afbSChen-Yu Tsai #define OV5640_TEST_ROLLING		BIT(6)	/* rolling horizontal bar */
3101a0c29afbSChen-Yu Tsai #define OV5640_TEST_TRANSPARENT		BIT(5)
3102a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE_BW		BIT(4)	/* black & white squares */
3103a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_STANDARD	(0 << 2)
3104a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_1	(1 << 2)
3105a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_HOR_CHANGE	(2 << 2)
3106a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_2	(3 << 2)
3107a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR			(0 << 0)
3108a0c29afbSChen-Yu Tsai #define OV5640_TEST_RANDOM		(1 << 0)
3109a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE		(2 << 0)
3110a0c29afbSChen-Yu Tsai #define OV5640_TEST_BLACK		(3 << 0)
3111a0c29afbSChen-Yu Tsai 
3112a0c29afbSChen-Yu Tsai static const u8 test_pattern_val[] = {
3113a0c29afbSChen-Yu Tsai 	0,
31142aff1fc3SChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_BAR_VERT_CHANGE_1 |
3115a0c29afbSChen-Yu Tsai 		OV5640_TEST_BAR,
3116bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_ROLLING |
3117bddc5cdfSChen-Yu Tsai 		OV5640_TEST_BAR_VERT_CHANGE_1 | OV5640_TEST_BAR,
3118bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_SQUARE,
3119bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_ROLLING | OV5640_TEST_SQUARE,
3120a0c29afbSChen-Yu Tsai };
3121a0c29afbSChen-Yu Tsai 
312219a81c14SSteve Longerbeam static int ov5640_set_ctrl_test_pattern(struct ov5640_dev *sensor, int value)
312319a81c14SSteve Longerbeam {
3124a0c29afbSChen-Yu Tsai 	return ov5640_write_reg(sensor, OV5640_REG_PRE_ISP_TEST_SET1,
3125a0c29afbSChen-Yu Tsai 				test_pattern_val[value]);
312619a81c14SSteve Longerbeam }
312719a81c14SSteve Longerbeam 
31281068fecaSMylène Josserand static int ov5640_set_ctrl_light_freq(struct ov5640_dev *sensor, int value)
31291068fecaSMylène Josserand {
31301068fecaSMylène Josserand 	int ret;
31311068fecaSMylène Josserand 
31321068fecaSMylène Josserand 	ret = ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL01, BIT(7),
31331068fecaSMylène Josserand 			     (value == V4L2_CID_POWER_LINE_FREQUENCY_AUTO) ?
31341068fecaSMylène Josserand 			     0 : BIT(7));
31351068fecaSMylène Josserand 	if (ret)
31361068fecaSMylène Josserand 		return ret;
31371068fecaSMylène Josserand 
31381068fecaSMylène Josserand 	return ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL00, BIT(2),
31391068fecaSMylène Josserand 			      (value == V4L2_CID_POWER_LINE_FREQUENCY_50HZ) ?
31401068fecaSMylène Josserand 			      BIT(2) : 0);
31411068fecaSMylène Josserand }
31421068fecaSMylène Josserand 
3143ce85705aSHugues Fruchet static int ov5640_set_ctrl_hflip(struct ov5640_dev *sensor, int value)
3144ce85705aSHugues Fruchet {
3145ce85705aSHugues Fruchet 	/*
3146c3f3ba3eSHugues Fruchet 	 * If sensor is mounted upside down, mirror logic is inversed.
3147c3f3ba3eSHugues Fruchet 	 *
3148ce85705aSHugues Fruchet 	 * Sensor is a BSI (Back Side Illuminated) one,
3149ce85705aSHugues Fruchet 	 * so image captured is physically mirrored.
3150ce85705aSHugues Fruchet 	 * This is why mirror logic is inversed in
3151ce85705aSHugues Fruchet 	 * order to cancel this mirror effect.
3152ce85705aSHugues Fruchet 	 */
3153ce85705aSHugues Fruchet 
3154ce85705aSHugues Fruchet 	/*
3155ce85705aSHugues Fruchet 	 * TIMING TC REG21:
3156ce85705aSHugues Fruchet 	 * - [2]:	ISP mirror
3157ce85705aSHugues Fruchet 	 * - [1]:	Sensor mirror
3158ce85705aSHugues Fruchet 	 */
3159ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
3160ce85705aSHugues Fruchet 			      BIT(2) | BIT(1),
3161c3f3ba3eSHugues Fruchet 			      (!(value ^ sensor->upside_down)) ?
3162c3f3ba3eSHugues Fruchet 			      (BIT(2) | BIT(1)) : 0);
3163ce85705aSHugues Fruchet }
3164ce85705aSHugues Fruchet 
3165ce85705aSHugues Fruchet static int ov5640_set_ctrl_vflip(struct ov5640_dev *sensor, int value)
3166ce85705aSHugues Fruchet {
3167c3f3ba3eSHugues Fruchet 	/* If sensor is mounted upside down, flip logic is inversed */
3168c3f3ba3eSHugues Fruchet 
3169ce85705aSHugues Fruchet 	/*
3170ce85705aSHugues Fruchet 	 * TIMING TC REG20:
3171ce85705aSHugues Fruchet 	 * - [2]:	ISP vflip
3172ce85705aSHugues Fruchet 	 * - [1]:	Sensor vflip
3173ce85705aSHugues Fruchet 	 */
3174ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20,
3175ce85705aSHugues Fruchet 			      BIT(2) | BIT(1),
3176c3f3ba3eSHugues Fruchet 			      (value ^ sensor->upside_down) ?
3177c3f3ba3eSHugues Fruchet 			      (BIT(2) | BIT(1)) : 0);
3178ce85705aSHugues Fruchet }
3179ce85705aSHugues Fruchet 
3180bce93b82SJacopo Mondi static int ov5640_set_ctrl_vblank(struct ov5640_dev *sensor, int value)
3181bce93b82SJacopo Mondi {
3182bce93b82SJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
3183bce93b82SJacopo Mondi 
3184bce93b82SJacopo Mondi 	/* Update the VTOT timing register value. */
3185bce93b82SJacopo Mondi 	return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS,
3186bce93b82SJacopo Mondi 				  mode->height + value);
3187bce93b82SJacopo Mondi }
3188bce93b82SJacopo Mondi 
318919a81c14SSteve Longerbeam static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
319019a81c14SSteve Longerbeam {
319119a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
319219a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
319319a81c14SSteve Longerbeam 	int val;
319419a81c14SSteve Longerbeam 
319519a81c14SSteve Longerbeam 	/* v4l2_ctrl_lock() locks our own mutex */
319619a81c14SSteve Longerbeam 
319719a81c14SSteve Longerbeam 	switch (ctrl->id) {
319819a81c14SSteve Longerbeam 	case V4L2_CID_AUTOGAIN:
319919a81c14SSteve Longerbeam 		val = ov5640_get_gain(sensor);
320019a81c14SSteve Longerbeam 		if (val < 0)
320119a81c14SSteve Longerbeam 			return val;
320219a81c14SSteve Longerbeam 		sensor->ctrls.gain->val = val;
320319a81c14SSteve Longerbeam 		break;
320419a81c14SSteve Longerbeam 	case V4L2_CID_EXPOSURE_AUTO:
320519a81c14SSteve Longerbeam 		val = ov5640_get_exposure(sensor);
320619a81c14SSteve Longerbeam 		if (val < 0)
320719a81c14SSteve Longerbeam 			return val;
320819a81c14SSteve Longerbeam 		sensor->ctrls.exposure->val = val;
320919a81c14SSteve Longerbeam 		break;
321019a81c14SSteve Longerbeam 	}
321119a81c14SSteve Longerbeam 
321219a81c14SSteve Longerbeam 	return 0;
321319a81c14SSteve Longerbeam }
321419a81c14SSteve Longerbeam 
321519a81c14SSteve Longerbeam static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl)
321619a81c14SSteve Longerbeam {
321719a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
321819a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
3219bce93b82SJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
3220bce93b82SJacopo Mondi 	const struct ov5640_timings *timings;
3221bce93b82SJacopo Mondi 	unsigned int exp_max;
322219a81c14SSteve Longerbeam 	int ret;
322319a81c14SSteve Longerbeam 
322419a81c14SSteve Longerbeam 	/* v4l2_ctrl_lock() locks our own mutex */
322519a81c14SSteve Longerbeam 
3226bce93b82SJacopo Mondi 	switch (ctrl->id) {
3227bce93b82SJacopo Mondi 	case V4L2_CID_VBLANK:
3228bce93b82SJacopo Mondi 		/* Update the exposure range to the newly programmed vblank. */
3229bce93b82SJacopo Mondi 		timings = ov5640_timings(sensor, mode);
3230bce93b82SJacopo Mondi 		exp_max = mode->height + ctrl->val - 4;
3231bce93b82SJacopo Mondi 		__v4l2_ctrl_modify_range(sensor->ctrls.exposure,
3232bce93b82SJacopo Mondi 					 sensor->ctrls.exposure->minimum,
3233bce93b82SJacopo Mondi 					 exp_max, sensor->ctrls.exposure->step,
3234bce93b82SJacopo Mondi 					 timings->vblank_def);
3235bce93b82SJacopo Mondi 		break;
3236bce93b82SJacopo Mondi 	}
3237bce93b82SJacopo Mondi 
323819a81c14SSteve Longerbeam 	/*
323919a81c14SSteve Longerbeam 	 * If the device is not powered up by the host driver do
324019a81c14SSteve Longerbeam 	 * not apply any controls to H/W at this time. Instead
324119a81c14SSteve Longerbeam 	 * the controls will be restored right after power-up.
324219a81c14SSteve Longerbeam 	 */
324319a81c14SSteve Longerbeam 	if (sensor->power_count == 0)
324419a81c14SSteve Longerbeam 		return 0;
324519a81c14SSteve Longerbeam 
324619a81c14SSteve Longerbeam 	switch (ctrl->id) {
324719a81c14SSteve Longerbeam 	case V4L2_CID_AUTOGAIN:
324819a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_gain(sensor, ctrl->val);
324919a81c14SSteve Longerbeam 		break;
325019a81c14SSteve Longerbeam 	case V4L2_CID_EXPOSURE_AUTO:
325119a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_exposure(sensor, ctrl->val);
325219a81c14SSteve Longerbeam 		break;
325319a81c14SSteve Longerbeam 	case V4L2_CID_AUTO_WHITE_BALANCE:
325419a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_white_balance(sensor, ctrl->val);
325519a81c14SSteve Longerbeam 		break;
325619a81c14SSteve Longerbeam 	case V4L2_CID_HUE:
325719a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_hue(sensor, ctrl->val);
325819a81c14SSteve Longerbeam 		break;
325919a81c14SSteve Longerbeam 	case V4L2_CID_CONTRAST:
326019a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_contrast(sensor, ctrl->val);
326119a81c14SSteve Longerbeam 		break;
326219a81c14SSteve Longerbeam 	case V4L2_CID_SATURATION:
326319a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_saturation(sensor, ctrl->val);
326419a81c14SSteve Longerbeam 		break;
326519a81c14SSteve Longerbeam 	case V4L2_CID_TEST_PATTERN:
326619a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_test_pattern(sensor, ctrl->val);
326719a81c14SSteve Longerbeam 		break;
32681068fecaSMylène Josserand 	case V4L2_CID_POWER_LINE_FREQUENCY:
32691068fecaSMylène Josserand 		ret = ov5640_set_ctrl_light_freq(sensor, ctrl->val);
32701068fecaSMylène Josserand 		break;
3271ce85705aSHugues Fruchet 	case V4L2_CID_HFLIP:
3272ce85705aSHugues Fruchet 		ret = ov5640_set_ctrl_hflip(sensor, ctrl->val);
3273ce85705aSHugues Fruchet 		break;
3274ce85705aSHugues Fruchet 	case V4L2_CID_VFLIP:
3275ce85705aSHugues Fruchet 		ret = ov5640_set_ctrl_vflip(sensor, ctrl->val);
3276ce85705aSHugues Fruchet 		break;
3277bce93b82SJacopo Mondi 	case V4L2_CID_VBLANK:
3278bce93b82SJacopo Mondi 		ret = ov5640_set_ctrl_vblank(sensor, ctrl->val);
3279bce93b82SJacopo Mondi 		break;
328019a81c14SSteve Longerbeam 	default:
328119a81c14SSteve Longerbeam 		ret = -EINVAL;
328219a81c14SSteve Longerbeam 		break;
328319a81c14SSteve Longerbeam 	}
328419a81c14SSteve Longerbeam 
328519a81c14SSteve Longerbeam 	return ret;
328619a81c14SSteve Longerbeam }
328719a81c14SSteve Longerbeam 
328819a81c14SSteve Longerbeam static const struct v4l2_ctrl_ops ov5640_ctrl_ops = {
328919a81c14SSteve Longerbeam 	.g_volatile_ctrl = ov5640_g_volatile_ctrl,
329019a81c14SSteve Longerbeam 	.s_ctrl = ov5640_s_ctrl,
329119a81c14SSteve Longerbeam };
329219a81c14SSteve Longerbeam 
329319a81c14SSteve Longerbeam static int ov5640_init_controls(struct ov5640_dev *sensor)
329419a81c14SSteve Longerbeam {
329522845bf2SJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
329619a81c14SSteve Longerbeam 	const struct v4l2_ctrl_ops *ops = &ov5640_ctrl_ops;
329719a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
329819a81c14SSteve Longerbeam 	struct v4l2_ctrl_handler *hdl = &ctrls->handler;
329932979f67SJacopo Mondi 	const struct ov5640_timings *timings;
3300bce93b82SJacopo Mondi 	unsigned int max_vblank;
330132979f67SJacopo Mondi 	unsigned int hblank;
330219a81c14SSteve Longerbeam 	int ret;
330319a81c14SSteve Longerbeam 
330419a81c14SSteve Longerbeam 	v4l2_ctrl_handler_init(hdl, 32);
330519a81c14SSteve Longerbeam 
330619a81c14SSteve Longerbeam 	/* we can use our own mutex for the ctrl lock */
330719a81c14SSteve Longerbeam 	hdl->lock = &sensor->lock;
330819a81c14SSteve Longerbeam 
3309cc196e48SBenoit Parrot 	/* Clock related controls */
3310cc196e48SBenoit Parrot 	ctrls->pixel_rate = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE,
331122845bf2SJacopo Mondi 			      ov5640_pixel_rates[OV5640_NUM_PIXEL_RATES - 1],
331222845bf2SJacopo Mondi 			      ov5640_pixel_rates[0], 1,
331322845bf2SJacopo Mondi 			      ov5640_pixel_rates[mode->pixel_rate]);
3314cc196e48SBenoit Parrot 
33157a3b8d4bSJacopo Mondi 	ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops,
33167a3b8d4bSJacopo Mondi 					V4L2_CID_LINK_FREQ,
33177a3b8d4bSJacopo Mondi 					ARRAY_SIZE(ov5640_csi2_link_freqs) - 1,
33187a3b8d4bSJacopo Mondi 					OV5640_DEFAULT_LINK_FREQ,
33197a3b8d4bSJacopo Mondi 					ov5640_csi2_link_freqs);
33207a3b8d4bSJacopo Mondi 
332132979f67SJacopo Mondi 	timings = ov5640_timings(sensor, mode);
332232979f67SJacopo Mondi 	hblank = timings->htot - mode->width;
332332979f67SJacopo Mondi 	ctrls->hblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HBLANK, hblank,
332432979f67SJacopo Mondi 					  hblank, 1, hblank);
332532979f67SJacopo Mondi 
3326bce93b82SJacopo Mondi 	max_vblank = OV5640_MAX_VTS - mode->height;
3327bce93b82SJacopo Mondi 	ctrls->vblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VBLANK,
3328bce93b82SJacopo Mondi 					  OV5640_MIN_VBLANK, max_vblank,
3329bce93b82SJacopo Mondi 					  1, timings->vblank_def);
3330bce93b82SJacopo Mondi 
333119a81c14SSteve Longerbeam 	/* Auto/manual white balance */
333219a81c14SSteve Longerbeam 	ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops,
333319a81c14SSteve Longerbeam 					   V4L2_CID_AUTO_WHITE_BALANCE,
333419a81c14SSteve Longerbeam 					   0, 1, 1, 1);
333519a81c14SSteve Longerbeam 	ctrls->blue_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BLUE_BALANCE,
333619a81c14SSteve Longerbeam 						0, 4095, 1, 0);
333719a81c14SSteve Longerbeam 	ctrls->red_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_RED_BALANCE,
333819a81c14SSteve Longerbeam 					       0, 4095, 1, 0);
333919a81c14SSteve Longerbeam 	/* Auto/manual exposure */
334019a81c14SSteve Longerbeam 	ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops,
334119a81c14SSteve Longerbeam 						 V4L2_CID_EXPOSURE_AUTO,
334219a81c14SSteve Longerbeam 						 V4L2_EXPOSURE_MANUAL, 0,
334319a81c14SSteve Longerbeam 						 V4L2_EXPOSURE_AUTO);
334419a81c14SSteve Longerbeam 	ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
334519a81c14SSteve Longerbeam 					    0, 65535, 1, 0);
334619a81c14SSteve Longerbeam 	/* Auto/manual gain */
334719a81c14SSteve Longerbeam 	ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN,
334819a81c14SSteve Longerbeam 					     0, 1, 1, 1);
334919a81c14SSteve Longerbeam 	ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN,
335019a81c14SSteve Longerbeam 					0, 1023, 1, 0);
335119a81c14SSteve Longerbeam 
335219a81c14SSteve Longerbeam 	ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION,
335319a81c14SSteve Longerbeam 					      0, 255, 1, 64);
335419a81c14SSteve Longerbeam 	ctrls->hue = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HUE,
335519a81c14SSteve Longerbeam 				       0, 359, 1, 0);
335619a81c14SSteve Longerbeam 	ctrls->contrast = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST,
335719a81c14SSteve Longerbeam 					    0, 255, 1, 0);
335819a81c14SSteve Longerbeam 	ctrls->test_pattern =
335919a81c14SSteve Longerbeam 		v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN,
336019a81c14SSteve Longerbeam 					     ARRAY_SIZE(test_pattern_menu) - 1,
336119a81c14SSteve Longerbeam 					     0, 0, test_pattern_menu);
3362ce85705aSHugues Fruchet 	ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP,
3363ce85705aSHugues Fruchet 					 0, 1, 1, 0);
3364ce85705aSHugues Fruchet 	ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP,
3365ce85705aSHugues Fruchet 					 0, 1, 1, 0);
336619a81c14SSteve Longerbeam 
33671068fecaSMylène Josserand 	ctrls->light_freq =
33681068fecaSMylène Josserand 		v4l2_ctrl_new_std_menu(hdl, ops,
33691068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY,
33701068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
33711068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
33721068fecaSMylène Josserand 
337319a81c14SSteve Longerbeam 	if (hdl->error) {
337419a81c14SSteve Longerbeam 		ret = hdl->error;
337519a81c14SSteve Longerbeam 		goto free_ctrls;
337619a81c14SSteve Longerbeam 	}
337719a81c14SSteve Longerbeam 
3378cc196e48SBenoit Parrot 	ctrls->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY;
33797a3b8d4bSJacopo Mondi 	ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
338032979f67SJacopo Mondi 	ctrls->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
338119a81c14SSteve Longerbeam 	ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE;
338219a81c14SSteve Longerbeam 	ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE;
338319a81c14SSteve Longerbeam 
338419a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false);
338519a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(2, &ctrls->auto_gain, 0, true);
338619a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(2, &ctrls->auto_exp, 1, true);
338719a81c14SSteve Longerbeam 
338819a81c14SSteve Longerbeam 	sensor->sd.ctrl_handler = hdl;
338919a81c14SSteve Longerbeam 	return 0;
339019a81c14SSteve Longerbeam 
339119a81c14SSteve Longerbeam free_ctrls:
339219a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(hdl);
339319a81c14SSteve Longerbeam 	return ret;
339419a81c14SSteve Longerbeam }
339519a81c14SSteve Longerbeam 
339619a81c14SSteve Longerbeam static int ov5640_enum_frame_size(struct v4l2_subdev *sd,
33970d346d2aSTomi Valkeinen 				  struct v4l2_subdev_state *sd_state,
339819a81c14SSteve Longerbeam 				  struct v4l2_subdev_frame_size_enum *fse)
339919a81c14SSteve Longerbeam {
340019a81c14SSteve Longerbeam 	if (fse->pad != 0)
340119a81c14SSteve Longerbeam 		return -EINVAL;
340219a81c14SSteve Longerbeam 	if (fse->index >= OV5640_NUM_MODES)
340319a81c14SSteve Longerbeam 		return -EINVAL;
340419a81c14SSteve Longerbeam 
34055113d5b3SJacopo Mondi 	fse->min_width = ov5640_mode_data[fse->index].width;
340641d8d7f5SHugues Fruchet 	fse->max_width = fse->min_width;
34075113d5b3SJacopo Mondi 	fse->min_height = ov5640_mode_data[fse->index].height;
340841d8d7f5SHugues Fruchet 	fse->max_height = fse->min_height;
340919a81c14SSteve Longerbeam 
341019a81c14SSteve Longerbeam 	return 0;
341119a81c14SSteve Longerbeam }
341219a81c14SSteve Longerbeam 
341319a81c14SSteve Longerbeam static int ov5640_enum_frame_interval(
341419a81c14SSteve Longerbeam 	struct v4l2_subdev *sd,
34150d346d2aSTomi Valkeinen 	struct v4l2_subdev_state *sd_state,
341619a81c14SSteve Longerbeam 	struct v4l2_subdev_frame_interval_enum *fie)
341719a81c14SSteve Longerbeam {
341819a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
341919a81c14SSteve Longerbeam 	struct v4l2_fract tpf;
342019a81c14SSteve Longerbeam 	int ret;
342119a81c14SSteve Longerbeam 
342219a81c14SSteve Longerbeam 	if (fie->pad != 0)
342319a81c14SSteve Longerbeam 		return -EINVAL;
342419a81c14SSteve Longerbeam 	if (fie->index >= OV5640_NUM_FRAMERATES)
342519a81c14SSteve Longerbeam 		return -EINVAL;
342619a81c14SSteve Longerbeam 
342719a81c14SSteve Longerbeam 	tpf.numerator = 1;
342819a81c14SSteve Longerbeam 	tpf.denominator = ov5640_framerates[fie->index];
342919a81c14SSteve Longerbeam 
343019a81c14SSteve Longerbeam 	ret = ov5640_try_frame_interval(sensor, &tpf,
343119a81c14SSteve Longerbeam 					fie->width, fie->height);
343219a81c14SSteve Longerbeam 	if (ret < 0)
343319a81c14SSteve Longerbeam 		return -EINVAL;
343419a81c14SSteve Longerbeam 
343519a81c14SSteve Longerbeam 	fie->interval = tpf;
343619a81c14SSteve Longerbeam 	return 0;
343719a81c14SSteve Longerbeam }
343819a81c14SSteve Longerbeam 
343919a81c14SSteve Longerbeam static int ov5640_g_frame_interval(struct v4l2_subdev *sd,
344019a81c14SSteve Longerbeam 				   struct v4l2_subdev_frame_interval *fi)
344119a81c14SSteve Longerbeam {
344219a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
344319a81c14SSteve Longerbeam 
344419a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
344519a81c14SSteve Longerbeam 	fi->interval = sensor->frame_interval;
344619a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
344719a81c14SSteve Longerbeam 
344819a81c14SSteve Longerbeam 	return 0;
344919a81c14SSteve Longerbeam }
345019a81c14SSteve Longerbeam 
345119a81c14SSteve Longerbeam static int ov5640_s_frame_interval(struct v4l2_subdev *sd,
345219a81c14SSteve Longerbeam 				   struct v4l2_subdev_frame_interval *fi)
345319a81c14SSteve Longerbeam {
345419a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
345519a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
345619a81c14SSteve Longerbeam 	int frame_rate, ret = 0;
345719a81c14SSteve Longerbeam 
345819a81c14SSteve Longerbeam 	if (fi->pad != 0)
345919a81c14SSteve Longerbeam 		return -EINVAL;
346019a81c14SSteve Longerbeam 
346119a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
346219a81c14SSteve Longerbeam 
346319a81c14SSteve Longerbeam 	if (sensor->streaming) {
346419a81c14SSteve Longerbeam 		ret = -EBUSY;
346519a81c14SSteve Longerbeam 		goto out;
346619a81c14SSteve Longerbeam 	}
346719a81c14SSteve Longerbeam 
346819a81c14SSteve Longerbeam 	mode = sensor->current_mode;
346919a81c14SSteve Longerbeam 
347019a81c14SSteve Longerbeam 	frame_rate = ov5640_try_frame_interval(sensor, &fi->interval,
34715113d5b3SJacopo Mondi 					       mode->width,
34725113d5b3SJacopo Mondi 					       mode->height);
3473e823fb16SMaxime Ripard 	if (frame_rate < 0) {
3474e823fb16SMaxime Ripard 		/* Always return a valid frame interval value */
3475e823fb16SMaxime Ripard 		fi->interval = sensor->frame_interval;
3476e823fb16SMaxime Ripard 		goto out;
3477e823fb16SMaxime Ripard 	}
347819a81c14SSteve Longerbeam 
3479*b6ae5022SJacopo Mondi 	mode = ov5640_find_mode(sensor, mode->width, mode->height, true);
34803c4a7372SHugues Fruchet 	if (!mode) {
34813c4a7372SHugues Fruchet 		ret = -EINVAL;
34823c4a7372SHugues Fruchet 		goto out;
34833c4a7372SHugues Fruchet 	}
34843c4a7372SHugues Fruchet 
3485*b6ae5022SJacopo Mondi 	if (ov5640_framerates[frame_rate] > ov5640_framerates[mode->max_fps]) {
3486*b6ae5022SJacopo Mondi 		ret = -EINVAL;
3487*b6ae5022SJacopo Mondi 		goto out;
3488*b6ae5022SJacopo Mondi 	}
3489*b6ae5022SJacopo Mondi 
34900929983eSHugues Fruchet 	if (mode != sensor->current_mode ||
34910929983eSHugues Fruchet 	    frame_rate != sensor->current_fr) {
34920929983eSHugues Fruchet 		sensor->current_fr = frame_rate;
34930929983eSHugues Fruchet 		sensor->frame_interval = fi->interval;
34943c4a7372SHugues Fruchet 		sensor->current_mode = mode;
349519a81c14SSteve Longerbeam 		sensor->pending_mode_change = true;
3496cc196e48SBenoit Parrot 
349719f2e3e6SHugues Fruchet 		ov5640_update_pixel_rate(sensor);
34986949d864SHugues Fruchet 	}
349919a81c14SSteve Longerbeam out:
350019a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
350119a81c14SSteve Longerbeam 	return ret;
350219a81c14SSteve Longerbeam }
350319a81c14SSteve Longerbeam 
350419a81c14SSteve Longerbeam static int ov5640_enum_mbus_code(struct v4l2_subdev *sd,
35050d346d2aSTomi Valkeinen 				 struct v4l2_subdev_state *sd_state,
350619a81c14SSteve Longerbeam 				 struct v4l2_subdev_mbus_code_enum *code)
350719a81c14SSteve Longerbeam {
350819a81c14SSteve Longerbeam 	if (code->pad != 0)
350919a81c14SSteve Longerbeam 		return -EINVAL;
3510e3ee691dSHugues Fruchet 	if (code->index >= ARRAY_SIZE(ov5640_formats))
351119a81c14SSteve Longerbeam 		return -EINVAL;
351219a81c14SSteve Longerbeam 
3513e3ee691dSHugues Fruchet 	code->code = ov5640_formats[code->index].code;
351419a81c14SSteve Longerbeam 	return 0;
351519a81c14SSteve Longerbeam }
351619a81c14SSteve Longerbeam 
351719a81c14SSteve Longerbeam static int ov5640_s_stream(struct v4l2_subdev *sd, int enable)
351819a81c14SSteve Longerbeam {
351919a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
352019a81c14SSteve Longerbeam 	int ret = 0;
352119a81c14SSteve Longerbeam 
352219a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
352319a81c14SSteve Longerbeam 
352419a81c14SSteve Longerbeam 	if (sensor->streaming == !enable) {
352519a81c14SSteve Longerbeam 		if (enable && sensor->pending_mode_change) {
3526985cdcb0SHugues Fruchet 			ret = ov5640_set_mode(sensor);
352719a81c14SSteve Longerbeam 			if (ret)
352819a81c14SSteve Longerbeam 				goto out;
3529fb98e29fSHugues Fruchet 		}
3530e3ee691dSHugues Fruchet 
3531fb98e29fSHugues Fruchet 		if (enable && sensor->pending_fmt_change) {
3532e3ee691dSHugues Fruchet 			ret = ov5640_set_framefmt(sensor, &sensor->fmt);
3533e3ee691dSHugues Fruchet 			if (ret)
3534e3ee691dSHugues Fruchet 				goto out;
3535fb98e29fSHugues Fruchet 			sensor->pending_fmt_change = false;
353619a81c14SSteve Longerbeam 		}
353719a81c14SSteve Longerbeam 
35388e823f5cSJacopo Mondi 		if (ov5640_is_csi2(sensor))
3539f22996dbSHugues Fruchet 			ret = ov5640_set_stream_mipi(sensor, enable);
3540f22996dbSHugues Fruchet 		else
3541f22996dbSHugues Fruchet 			ret = ov5640_set_stream_dvp(sensor, enable);
3542f22996dbSHugues Fruchet 
354319a81c14SSteve Longerbeam 		if (!ret)
354419a81c14SSteve Longerbeam 			sensor->streaming = enable;
354519a81c14SSteve Longerbeam 	}
354619a81c14SSteve Longerbeam out:
354719a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
354819a81c14SSteve Longerbeam 	return ret;
354919a81c14SSteve Longerbeam }
355019a81c14SSteve Longerbeam 
355119a81c14SSteve Longerbeam static const struct v4l2_subdev_core_ops ov5640_core_ops = {
355219a81c14SSteve Longerbeam 	.s_power = ov5640_s_power,
35532d18fbc5SAkinobu Mita 	.log_status = v4l2_ctrl_subdev_log_status,
35542d18fbc5SAkinobu Mita 	.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
35552d18fbc5SAkinobu Mita 	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
355619a81c14SSteve Longerbeam };
355719a81c14SSteve Longerbeam 
355819a81c14SSteve Longerbeam static const struct v4l2_subdev_video_ops ov5640_video_ops = {
355919a81c14SSteve Longerbeam 	.g_frame_interval = ov5640_g_frame_interval,
356019a81c14SSteve Longerbeam 	.s_frame_interval = ov5640_s_frame_interval,
356119a81c14SSteve Longerbeam 	.s_stream = ov5640_s_stream,
356219a81c14SSteve Longerbeam };
356319a81c14SSteve Longerbeam 
356419a81c14SSteve Longerbeam static const struct v4l2_subdev_pad_ops ov5640_pad_ops = {
356519a81c14SSteve Longerbeam 	.enum_mbus_code = ov5640_enum_mbus_code,
356619a81c14SSteve Longerbeam 	.get_fmt = ov5640_get_fmt,
356719a81c14SSteve Longerbeam 	.set_fmt = ov5640_set_fmt,
356819a81c14SSteve Longerbeam 	.enum_frame_size = ov5640_enum_frame_size,
356919a81c14SSteve Longerbeam 	.enum_frame_interval = ov5640_enum_frame_interval,
357019a81c14SSteve Longerbeam };
357119a81c14SSteve Longerbeam 
357219a81c14SSteve Longerbeam static const struct v4l2_subdev_ops ov5640_subdev_ops = {
357319a81c14SSteve Longerbeam 	.core = &ov5640_core_ops,
357419a81c14SSteve Longerbeam 	.video = &ov5640_video_ops,
357519a81c14SSteve Longerbeam 	.pad = &ov5640_pad_ops,
357619a81c14SSteve Longerbeam };
357719a81c14SSteve Longerbeam 
357819a81c14SSteve Longerbeam static int ov5640_get_regulators(struct ov5640_dev *sensor)
357919a81c14SSteve Longerbeam {
358019a81c14SSteve Longerbeam 	int i;
358119a81c14SSteve Longerbeam 
358219a81c14SSteve Longerbeam 	for (i = 0; i < OV5640_NUM_SUPPLIES; i++)
358319a81c14SSteve Longerbeam 		sensor->supplies[i].supply = ov5640_supply_name[i];
358419a81c14SSteve Longerbeam 
358519a81c14SSteve Longerbeam 	return devm_regulator_bulk_get(&sensor->i2c_client->dev,
358619a81c14SSteve Longerbeam 				       OV5640_NUM_SUPPLIES,
358719a81c14SSteve Longerbeam 				       sensor->supplies);
358819a81c14SSteve Longerbeam }
358919a81c14SSteve Longerbeam 
35900f7acb52SHugues Fruchet static int ov5640_check_chip_id(struct ov5640_dev *sensor)
35910f7acb52SHugues Fruchet {
35920f7acb52SHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
35930f7acb52SHugues Fruchet 	int ret = 0;
35940f7acb52SHugues Fruchet 	u16 chip_id;
35950f7acb52SHugues Fruchet 
35960f7acb52SHugues Fruchet 	ret = ov5640_set_power_on(sensor);
35970f7acb52SHugues Fruchet 	if (ret)
35980f7acb52SHugues Fruchet 		return ret;
35990f7acb52SHugues Fruchet 
36000f7acb52SHugues Fruchet 	ret = ov5640_read_reg16(sensor, OV5640_REG_CHIP_ID, &chip_id);
36010f7acb52SHugues Fruchet 	if (ret) {
36020f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to read chip identifier\n",
36030f7acb52SHugues Fruchet 			__func__);
36040f7acb52SHugues Fruchet 		goto power_off;
36050f7acb52SHugues Fruchet 	}
36060f7acb52SHugues Fruchet 
36070f7acb52SHugues Fruchet 	if (chip_id != 0x5640) {
36080f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: wrong chip identifier, expected 0x5640, got 0x%x\n",
36090f7acb52SHugues Fruchet 			__func__, chip_id);
36100f7acb52SHugues Fruchet 		ret = -ENXIO;
36110f7acb52SHugues Fruchet 	}
36120f7acb52SHugues Fruchet 
36130f7acb52SHugues Fruchet power_off:
36140f7acb52SHugues Fruchet 	ov5640_set_power_off(sensor);
36150f7acb52SHugues Fruchet 	return ret;
36160f7acb52SHugues Fruchet }
36170f7acb52SHugues Fruchet 
3618e6714993SKieran Bingham static int ov5640_probe(struct i2c_client *client)
361919a81c14SSteve Longerbeam {
362019a81c14SSteve Longerbeam 	struct device *dev = &client->dev;
362119a81c14SSteve Longerbeam 	struct fwnode_handle *endpoint;
362219a81c14SSteve Longerbeam 	struct ov5640_dev *sensor;
3623e6441fdeSHugues Fruchet 	struct v4l2_mbus_framefmt *fmt;
3624c3f3ba3eSHugues Fruchet 	u32 rotation;
362519a81c14SSteve Longerbeam 	int ret;
362619a81c14SSteve Longerbeam 
362719a81c14SSteve Longerbeam 	sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
362819a81c14SSteve Longerbeam 	if (!sensor)
362919a81c14SSteve Longerbeam 		return -ENOMEM;
363019a81c14SSteve Longerbeam 
363119a81c14SSteve Longerbeam 	sensor->i2c_client = client;
3632fb98e29fSHugues Fruchet 
3633fb98e29fSHugues Fruchet 	/*
3634fb98e29fSHugues Fruchet 	 * default init sequence initialize sensor to
3635fb98e29fSHugues Fruchet 	 * YUV422 UYVY VGA@30fps
3636fb98e29fSHugues Fruchet 	 */
3637e6441fdeSHugues Fruchet 	fmt = &sensor->fmt;
3638fb98e29fSHugues Fruchet 	fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
3639fb98e29fSHugues Fruchet 	fmt->colorspace = V4L2_COLORSPACE_SRGB;
3640e6441fdeSHugues Fruchet 	fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
3641e6441fdeSHugues Fruchet 	fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
3642e6441fdeSHugues Fruchet 	fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
3643e6441fdeSHugues Fruchet 	fmt->width = 640;
3644e6441fdeSHugues Fruchet 	fmt->height = 480;
3645e6441fdeSHugues Fruchet 	fmt->field = V4L2_FIELD_NONE;
364619a81c14SSteve Longerbeam 	sensor->frame_interval.numerator = 1;
364719a81c14SSteve Longerbeam 	sensor->frame_interval.denominator = ov5640_framerates[OV5640_30_FPS];
364819a81c14SSteve Longerbeam 	sensor->current_fr = OV5640_30_FPS;
364919a81c14SSteve Longerbeam 	sensor->current_mode =
3650086c25f8SMaxime Ripard 		&ov5640_mode_data[OV5640_MODE_VGA_640_480];
3651985cdcb0SHugues Fruchet 	sensor->last_mode = sensor->current_mode;
36523c28588fSJacopo Mondi 	sensor->current_link_freq = OV5640_DEFAULT_LINK_FREQ;
365319a81c14SSteve Longerbeam 
365419a81c14SSteve Longerbeam 	sensor->ae_target = 52;
365519a81c14SSteve Longerbeam 
3656c3f3ba3eSHugues Fruchet 	/* optional indication of physical rotation of sensor */
3657c3f3ba3eSHugues Fruchet 	ret = fwnode_property_read_u32(dev_fwnode(&client->dev), "rotation",
3658c3f3ba3eSHugues Fruchet 				       &rotation);
3659c3f3ba3eSHugues Fruchet 	if (!ret) {
3660c3f3ba3eSHugues Fruchet 		switch (rotation) {
3661c3f3ba3eSHugues Fruchet 		case 180:
3662c3f3ba3eSHugues Fruchet 			sensor->upside_down = true;
36631771e9fbSGustavo A. R. Silva 			fallthrough;
3664c3f3ba3eSHugues Fruchet 		case 0:
3665c3f3ba3eSHugues Fruchet 			break;
3666c3f3ba3eSHugues Fruchet 		default:
3667c3f3ba3eSHugues Fruchet 			dev_warn(dev, "%u degrees rotation is not supported, ignoring...\n",
3668c3f3ba3eSHugues Fruchet 				 rotation);
3669c3f3ba3eSHugues Fruchet 		}
3670c3f3ba3eSHugues Fruchet 	}
3671c3f3ba3eSHugues Fruchet 
3672ce96bcf5SSakari Ailus 	endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev),
3673ce96bcf5SSakari Ailus 						  NULL);
367419a81c14SSteve Longerbeam 	if (!endpoint) {
367519a81c14SSteve Longerbeam 		dev_err(dev, "endpoint node not found\n");
367619a81c14SSteve Longerbeam 		return -EINVAL;
367719a81c14SSteve Longerbeam 	}
367819a81c14SSteve Longerbeam 
367919a81c14SSteve Longerbeam 	ret = v4l2_fwnode_endpoint_parse(endpoint, &sensor->ep);
368019a81c14SSteve Longerbeam 	fwnode_handle_put(endpoint);
368119a81c14SSteve Longerbeam 	if (ret) {
368219a81c14SSteve Longerbeam 		dev_err(dev, "Could not parse endpoint\n");
368319a81c14SSteve Longerbeam 		return ret;
368419a81c14SSteve Longerbeam 	}
368519a81c14SSteve Longerbeam 
36862c61e48dSLad Prabhakar 	if (sensor->ep.bus_type != V4L2_MBUS_PARALLEL &&
36872c61e48dSLad Prabhakar 	    sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY &&
36882c61e48dSLad Prabhakar 	    sensor->ep.bus_type != V4L2_MBUS_BT656) {
36892c61e48dSLad Prabhakar 		dev_err(dev, "Unsupported bus type %d\n", sensor->ep.bus_type);
36902c61e48dSLad Prabhakar 		return -EINVAL;
36912c61e48dSLad Prabhakar 	}
36922c61e48dSLad Prabhakar 
369319a81c14SSteve Longerbeam 	/* get system clock (xclk) */
369419a81c14SSteve Longerbeam 	sensor->xclk = devm_clk_get(dev, "xclk");
369519a81c14SSteve Longerbeam 	if (IS_ERR(sensor->xclk)) {
369619a81c14SSteve Longerbeam 		dev_err(dev, "failed to get xclk\n");
369719a81c14SSteve Longerbeam 		return PTR_ERR(sensor->xclk);
369819a81c14SSteve Longerbeam 	}
369919a81c14SSteve Longerbeam 
370019a81c14SSteve Longerbeam 	sensor->xclk_freq = clk_get_rate(sensor->xclk);
370119a81c14SSteve Longerbeam 	if (sensor->xclk_freq < OV5640_XCLK_MIN ||
370219a81c14SSteve Longerbeam 	    sensor->xclk_freq > OV5640_XCLK_MAX) {
370319a81c14SSteve Longerbeam 		dev_err(dev, "xclk frequency out of range: %d Hz\n",
370419a81c14SSteve Longerbeam 			sensor->xclk_freq);
370519a81c14SSteve Longerbeam 		return -EINVAL;
370619a81c14SSteve Longerbeam 	}
370719a81c14SSteve Longerbeam 
370819a81c14SSteve Longerbeam 	/* request optional power down pin */
370919a81c14SSteve Longerbeam 	sensor->pwdn_gpio = devm_gpiod_get_optional(dev, "powerdown",
371019a81c14SSteve Longerbeam 						    GPIOD_OUT_HIGH);
37118791a102SFabio Estevam 	if (IS_ERR(sensor->pwdn_gpio))
37128791a102SFabio Estevam 		return PTR_ERR(sensor->pwdn_gpio);
37138791a102SFabio Estevam 
371419a81c14SSteve Longerbeam 	/* request optional reset pin */
371519a81c14SSteve Longerbeam 	sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset",
371619a81c14SSteve Longerbeam 						     GPIOD_OUT_HIGH);
37178791a102SFabio Estevam 	if (IS_ERR(sensor->reset_gpio))
37188791a102SFabio Estevam 		return PTR_ERR(sensor->reset_gpio);
371919a81c14SSteve Longerbeam 
372019a81c14SSteve Longerbeam 	v4l2_i2c_subdev_init(&sensor->sd, client, &ov5640_subdev_ops);
372119a81c14SSteve Longerbeam 
37222d18fbc5SAkinobu Mita 	sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
37232d18fbc5SAkinobu Mita 			    V4L2_SUBDEV_FL_HAS_EVENTS;
372419a81c14SSteve Longerbeam 	sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
372519a81c14SSteve Longerbeam 	sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
372619a81c14SSteve Longerbeam 	ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
372719a81c14SSteve Longerbeam 	if (ret)
372819a81c14SSteve Longerbeam 		return ret;
372919a81c14SSteve Longerbeam 
373019a81c14SSteve Longerbeam 	ret = ov5640_get_regulators(sensor);
373119a81c14SSteve Longerbeam 	if (ret)
373219a81c14SSteve Longerbeam 		return ret;
373319a81c14SSteve Longerbeam 
373419a81c14SSteve Longerbeam 	mutex_init(&sensor->lock);
373519a81c14SSteve Longerbeam 
37360f7acb52SHugues Fruchet 	ret = ov5640_check_chip_id(sensor);
37370f7acb52SHugues Fruchet 	if (ret)
37380f7acb52SHugues Fruchet 		goto entity_cleanup;
37390f7acb52SHugues Fruchet 
374019a81c14SSteve Longerbeam 	ret = ov5640_init_controls(sensor);
374119a81c14SSteve Longerbeam 	if (ret)
374219a81c14SSteve Longerbeam 		goto entity_cleanup;
374319a81c14SSteve Longerbeam 
374415786f7bSSakari Ailus 	ret = v4l2_async_register_subdev_sensor(&sensor->sd);
374519a81c14SSteve Longerbeam 	if (ret)
374619a81c14SSteve Longerbeam 		goto free_ctrls;
374719a81c14SSteve Longerbeam 
374819a81c14SSteve Longerbeam 	return 0;
374919a81c14SSteve Longerbeam 
375019a81c14SSteve Longerbeam free_ctrls:
375119a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
375219a81c14SSteve Longerbeam entity_cleanup:
375319a81c14SSteve Longerbeam 	media_entity_cleanup(&sensor->sd.entity);
3754bfcba38dSTomi Valkeinen 	mutex_destroy(&sensor->lock);
375519a81c14SSteve Longerbeam 	return ret;
375619a81c14SSteve Longerbeam }
375719a81c14SSteve Longerbeam 
375819a81c14SSteve Longerbeam static int ov5640_remove(struct i2c_client *client)
375919a81c14SSteve Longerbeam {
376019a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
376119a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
376219a81c14SSteve Longerbeam 
376319a81c14SSteve Longerbeam 	v4l2_async_unregister_subdev(&sensor->sd);
376419a81c14SSteve Longerbeam 	media_entity_cleanup(&sensor->sd.entity);
376519a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
3766bfcba38dSTomi Valkeinen 	mutex_destroy(&sensor->lock);
376719a81c14SSteve Longerbeam 
376819a81c14SSteve Longerbeam 	return 0;
376919a81c14SSteve Longerbeam }
377019a81c14SSteve Longerbeam 
377119a81c14SSteve Longerbeam static const struct i2c_device_id ov5640_id[] = {
377219a81c14SSteve Longerbeam 	{"ov5640", 0},
377319a81c14SSteve Longerbeam 	{},
377419a81c14SSteve Longerbeam };
377519a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(i2c, ov5640_id);
377619a81c14SSteve Longerbeam 
377719a81c14SSteve Longerbeam static const struct of_device_id ov5640_dt_ids[] = {
377819a81c14SSteve Longerbeam 	{ .compatible = "ovti,ov5640" },
377919a81c14SSteve Longerbeam 	{ /* sentinel */ }
378019a81c14SSteve Longerbeam };
378119a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(of, ov5640_dt_ids);
378219a81c14SSteve Longerbeam 
378319a81c14SSteve Longerbeam static struct i2c_driver ov5640_i2c_driver = {
378419a81c14SSteve Longerbeam 	.driver = {
378519a81c14SSteve Longerbeam 		.name  = "ov5640",
378619a81c14SSteve Longerbeam 		.of_match_table	= ov5640_dt_ids,
378719a81c14SSteve Longerbeam 	},
378819a81c14SSteve Longerbeam 	.id_table = ov5640_id,
3789e6714993SKieran Bingham 	.probe_new = ov5640_probe,
379019a81c14SSteve Longerbeam 	.remove   = ov5640_remove,
379119a81c14SSteve Longerbeam };
379219a81c14SSteve Longerbeam 
379319a81c14SSteve Longerbeam module_i2c_driver(ov5640_i2c_driver);
379419a81c14SSteve Longerbeam 
379519a81c14SSteve Longerbeam MODULE_DESCRIPTION("OV5640 MIPI Camera Subdev Driver");
379619a81c14SSteve Longerbeam MODULE_LICENSE("GPL");
3797