xref: /openbmc/linux/drivers/media/i2c/ov5640.c (revision db15c195)
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 
3919a81c14SSteve Longerbeam #define OV5640_DEFAULT_SLAVE_ID 0x3c
4019a81c14SSteve Longerbeam 
413c28588fSJacopo Mondi #define OV5640_LINK_RATE_MAX		490000000U
423c28588fSJacopo Mondi 
43d47c4126SHugues Fruchet #define OV5640_REG_SYS_RESET02		0x3002
44d47c4126SHugues Fruchet #define OV5640_REG_SYS_CLOCK_ENABLE02	0x3006
45f22996dbSHugues Fruchet #define OV5640_REG_SYS_CTRL0		0x3008
463b987d70SLad Prabhakar #define OV5640_REG_SYS_CTRL0_SW_PWDN	0x42
473b987d70SLad Prabhakar #define OV5640_REG_SYS_CTRL0_SW_PWUP	0x02
4819a81c14SSteve Longerbeam #define OV5640_REG_CHIP_ID		0x300a
49f22996dbSHugues Fruchet #define OV5640_REG_IO_MIPI_CTRL00	0x300e
50f22996dbSHugues Fruchet #define OV5640_REG_PAD_OUTPUT_ENABLE01	0x3017
51f22996dbSHugues Fruchet #define OV5640_REG_PAD_OUTPUT_ENABLE02	0x3018
5219a81c14SSteve Longerbeam #define OV5640_REG_PAD_OUTPUT00		0x3019
53f22996dbSHugues Fruchet #define OV5640_REG_SYSTEM_CONTROL1	0x302e
5419a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL0		0x3034
5519a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL1		0x3035
5619a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL2		0x3036
5719a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL3		0x3037
5819a81c14SSteve Longerbeam #define OV5640_REG_SLAVE_ID		0x3100
59f22996dbSHugues Fruchet #define OV5640_REG_SCCB_SYS_CTRL1	0x3103
6019a81c14SSteve Longerbeam #define OV5640_REG_SYS_ROOT_DIVIDER	0x3108
6119a81c14SSteve Longerbeam #define OV5640_REG_AWB_R_GAIN		0x3400
6219a81c14SSteve Longerbeam #define OV5640_REG_AWB_G_GAIN		0x3402
6319a81c14SSteve Longerbeam #define OV5640_REG_AWB_B_GAIN		0x3404
6419a81c14SSteve Longerbeam #define OV5640_REG_AWB_MANUAL_CTRL	0x3406
6519a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_HI	0x3500
6619a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_MED	0x3501
6719a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_LO	0x3502
6819a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_MANUAL	0x3503
6919a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_REAL_GAIN	0x350a
7019a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_VTS		0x350c
713145efcdSJacopo Mondi #define OV5640_REG_TIMING_HS		0x3800
723145efcdSJacopo Mondi #define OV5640_REG_TIMING_VS		0x3802
733145efcdSJacopo Mondi #define OV5640_REG_TIMING_HW		0x3804
743145efcdSJacopo Mondi #define OV5640_REG_TIMING_VH		0x3806
7586633417SMaxime Ripard #define OV5640_REG_TIMING_DVPHO		0x3808
7686633417SMaxime Ripard #define OV5640_REG_TIMING_DVPVO		0x380a
7719a81c14SSteve Longerbeam #define OV5640_REG_TIMING_HTS		0x380c
7819a81c14SSteve Longerbeam #define OV5640_REG_TIMING_VTS		0x380e
793145efcdSJacopo Mondi #define OV5640_REG_TIMING_HOFFS		0x3810
803145efcdSJacopo Mondi #define OV5640_REG_TIMING_VOFFS		0x3812
81ce85705aSHugues Fruchet #define OV5640_REG_TIMING_TC_REG20	0x3820
8219a81c14SSteve Longerbeam #define OV5640_REG_TIMING_TC_REG21	0x3821
8319a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL00		0x3a00
8419a81c14SSteve Longerbeam #define OV5640_REG_AEC_B50_STEP		0x3a08
8519a81c14SSteve Longerbeam #define OV5640_REG_AEC_B60_STEP		0x3a0a
8619a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0D		0x3a0d
8719a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0E		0x3a0e
8819a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0F		0x3a0f
8919a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL10		0x3a10
9019a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL11		0x3a11
9119a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1B		0x3a1b
9219a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1E		0x3a1e
9319a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1F		0x3a1f
9419a81c14SSteve Longerbeam #define OV5640_REG_HZ5060_CTRL00	0x3c00
9519a81c14SSteve Longerbeam #define OV5640_REG_HZ5060_CTRL01	0x3c01
9619a81c14SSteve Longerbeam #define OV5640_REG_SIGMADELTA_CTRL0C	0x3c0c
9719a81c14SSteve Longerbeam #define OV5640_REG_FRAME_CTRL01		0x4202
98e3ee691dSHugues Fruchet #define OV5640_REG_FORMAT_CONTROL00	0x4300
997cb013b1SChen-Yu Tsai #define OV5640_REG_VFIFO_HSIZE		0x4602
1007cb013b1SChen-Yu Tsai #define OV5640_REG_VFIFO_VSIZE		0x4604
1012b5c18f9SChen-Yu Tsai #define OV5640_REG_JPG_MODE_SELECT	0x4713
1024039b037SLad Prabhakar #define OV5640_REG_CCIR656_CTRL00	0x4730
103f22996dbSHugues Fruchet #define OV5640_REG_POLARITY_CTRL00	0x4740
10419a81c14SSteve Longerbeam #define OV5640_REG_MIPI_CTRL00		0x4800
10519a81c14SSteve Longerbeam #define OV5640_REG_DEBUG_MODE		0x4814
1066c957ed7SJacopo Mondi #define OV5640_REG_PCLK_PERIOD		0x4837
107e3ee691dSHugues Fruchet #define OV5640_REG_ISP_FORMAT_MUX_CTRL	0x501f
10819a81c14SSteve Longerbeam #define OV5640_REG_PRE_ISP_TEST_SET1	0x503d
10919a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL0		0x5580
11019a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL1		0x5581
11119a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL3		0x5583
11219a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL4		0x5584
11319a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL5		0x5585
11419a81c14SSteve Longerbeam #define OV5640_REG_AVG_READOUT		0x56a1
11519a81c14SSteve Longerbeam 
11619a81c14SSteve Longerbeam enum ov5640_mode_id {
11732ea5e05SHugues Fruchet 	OV5640_MODE_QQVGA_160_120 = 0,
11832ea5e05SHugues Fruchet 	OV5640_MODE_QCIF_176_144,
11919a81c14SSteve Longerbeam 	OV5640_MODE_QVGA_320_240,
12019a81c14SSteve Longerbeam 	OV5640_MODE_VGA_640_480,
12119a81c14SSteve Longerbeam 	OV5640_MODE_NTSC_720_480,
12219a81c14SSteve Longerbeam 	OV5640_MODE_PAL_720_576,
12319a81c14SSteve Longerbeam 	OV5640_MODE_XGA_1024_768,
12419a81c14SSteve Longerbeam 	OV5640_MODE_720P_1280_720,
12519a81c14SSteve Longerbeam 	OV5640_MODE_1080P_1920_1080,
12619a81c14SSteve Longerbeam 	OV5640_MODE_QSXGA_2592_1944,
12719a81c14SSteve Longerbeam 	OV5640_NUM_MODES,
12819a81c14SSteve Longerbeam };
12919a81c14SSteve Longerbeam 
13019a81c14SSteve Longerbeam enum ov5640_frame_rate {
13119a81c14SSteve Longerbeam 	OV5640_15_FPS = 0,
13219a81c14SSteve Longerbeam 	OV5640_30_FPS,
133e823fb16SMaxime Ripard 	OV5640_60_FPS,
13419a81c14SSteve Longerbeam 	OV5640_NUM_FRAMERATES,
13519a81c14SSteve Longerbeam };
13619a81c14SSteve Longerbeam 
13722845bf2SJacopo Mondi enum ov5640_pixel_rate_id {
13822845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_168M,
13922845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_148M,
14022845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_124M,
14122845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_96M,
14222845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_48M,
14322845bf2SJacopo Mondi 	OV5640_NUM_PIXEL_RATES,
14422845bf2SJacopo Mondi };
14522845bf2SJacopo Mondi 
14622845bf2SJacopo Mondi /*
14722845bf2SJacopo Mondi  * The chip manual suggests 24/48/96/192 MHz pixel clocks.
14822845bf2SJacopo Mondi  *
14922845bf2SJacopo Mondi  * 192MHz exceeds the sysclk limits; use 168MHz as maximum pixel rate for
15022845bf2SJacopo Mondi  * full resolution mode @15 FPS.
15122845bf2SJacopo Mondi  */
15222845bf2SJacopo Mondi static const u32 ov5640_pixel_rates[] = {
15322845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_168M] = 168000000,
15422845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_148M] = 148000000,
15522845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_124M] = 124000000,
15622845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_96M] = 96000000,
15722845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_48M] = 48000000,
15822845bf2SJacopo Mondi };
15922845bf2SJacopo Mondi 
1607a3b8d4bSJacopo Mondi /*
1617a3b8d4bSJacopo Mondi  * MIPI CSI-2 link frequencies.
1627a3b8d4bSJacopo Mondi  *
1637a3b8d4bSJacopo Mondi  * Derived from the above defined pixel rate for bpp = (8, 16, 24) and
1647a3b8d4bSJacopo Mondi  * data_lanes = (1, 2)
1657a3b8d4bSJacopo Mondi  *
1667a3b8d4bSJacopo Mondi  * link_freq = (pixel_rate * bpp) / (2 * data_lanes)
1677a3b8d4bSJacopo Mondi  */
1687a3b8d4bSJacopo Mondi static const s64 ov5640_csi2_link_freqs[] = {
1697a3b8d4bSJacopo Mondi 	992000000, 888000000, 768000000, 744000000, 672000000, 672000000,
1707a3b8d4bSJacopo Mondi 	592000000, 592000000, 576000000, 576000000, 496000000, 496000000,
1717a3b8d4bSJacopo Mondi 	384000000, 384000000, 384000000, 336000000, 296000000, 288000000,
1727a3b8d4bSJacopo Mondi 	248000000, 192000000, 192000000, 192000000, 96000000,
1737a3b8d4bSJacopo Mondi };
1747a3b8d4bSJacopo Mondi 
1757a3b8d4bSJacopo Mondi /* Link freq for default mode: UYVY 16 bpp, 2 data lanes. */
1767a3b8d4bSJacopo Mondi #define OV5640_DEFAULT_LINK_FREQ	13
1777a3b8d4bSJacopo Mondi 
178b7ed3abdSLoic Poulain enum ov5640_format_mux {
179b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_YUV422 = 0,
180b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_RGB,
181b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_DITHER,
182b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_RAW_DPC,
183b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_SNR_RAW,
184b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_RAW_CIP,
185b7ed3abdSLoic Poulain };
186b7ed3abdSLoic Poulain 
1872d7671f6SJacopo Mondi static const struct ov5640_pixfmt {
188e3ee691dSHugues Fruchet 	u32 code;
189e3ee691dSHugues Fruchet 	u32 colorspace;
1902d7671f6SJacopo Mondi 	u8 bpp;
1912d7671f6SJacopo Mondi } ov5640_formats[] = {
1922d7671f6SJacopo Mondi 	{
1932d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_JPEG_1X8,
1942d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_JPEG,
1952d7671f6SJacopo Mondi 		.bpp = 16,
1962d7671f6SJacopo Mondi 	}, {
1972d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_UYVY8_2X8,
1982d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
1992d7671f6SJacopo Mondi 		.bpp = 16,
2002d7671f6SJacopo Mondi 	}, {
2012d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_UYVY8_1X16,
2022d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2032d7671f6SJacopo Mondi 		.bpp = 16,
2042d7671f6SJacopo Mondi 	}, {
2052d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_YUYV8_2X8,
2062d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2072d7671f6SJacopo Mondi 		.bpp = 16,
2082d7671f6SJacopo Mondi 	}, {
2092d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_YUYV8_1X16,
2102d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2112d7671f6SJacopo Mondi 		.bpp = 16,
2122d7671f6SJacopo Mondi 	}, {
2132d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_RGB565_2X8_LE,
2142d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2152d7671f6SJacopo Mondi 		.bpp = 16,
2162d7671f6SJacopo Mondi 	}, {
2172d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_RGB565_2X8_BE,
2182d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2192d7671f6SJacopo Mondi 		.bpp = 16,
2202d7671f6SJacopo Mondi 	}, {
2212d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_SBGGR8_1X8,
2222d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2232d7671f6SJacopo Mondi 		.bpp = 8,
2242d7671f6SJacopo Mondi 	}, {
2252d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_SGBRG8_1X8,
2262d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2272d7671f6SJacopo Mondi 		.bpp = 8
2282d7671f6SJacopo Mondi 	}, {
2292d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_SGRBG8_1X8,
2302d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2312d7671f6SJacopo Mondi 		.bpp = 8,
2322d7671f6SJacopo Mondi 	}, {
2332d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_SRGGB8_1X8,
2342d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2352d7671f6SJacopo Mondi 		.bpp = 8,
2362d7671f6SJacopo Mondi 	},
237e3ee691dSHugues Fruchet };
238e3ee691dSHugues Fruchet 
2393c28588fSJacopo Mondi static u32 ov5640_code_to_bpp(u32 code)
2403c28588fSJacopo Mondi {
2413c28588fSJacopo Mondi 	unsigned int i;
2423c28588fSJacopo Mondi 
2433c28588fSJacopo Mondi 	for (i = 0; i < ARRAY_SIZE(ov5640_formats); ++i) {
2443c28588fSJacopo Mondi 		if (ov5640_formats[i].code == code)
2453c28588fSJacopo Mondi 			return ov5640_formats[i].bpp;
2463c28588fSJacopo Mondi 	}
2473c28588fSJacopo Mondi 
2483c28588fSJacopo Mondi 	return 0;
2493c28588fSJacopo Mondi }
2503c28588fSJacopo Mondi 
25119a81c14SSteve Longerbeam /*
25219a81c14SSteve Longerbeam  * FIXME: remove this when a subdev API becomes available
25319a81c14SSteve Longerbeam  * to set the MIPI CSI-2 virtual channel.
25419a81c14SSteve Longerbeam  */
25519a81c14SSteve Longerbeam static unsigned int virtual_channel;
2568670d70aSHugues Fruchet module_param(virtual_channel, uint, 0444);
25719a81c14SSteve Longerbeam MODULE_PARM_DESC(virtual_channel,
25819a81c14SSteve Longerbeam 		 "MIPI CSI-2 virtual channel (0..3), default 0");
25919a81c14SSteve Longerbeam 
26019a81c14SSteve Longerbeam static const int ov5640_framerates[] = {
26119a81c14SSteve Longerbeam 	[OV5640_15_FPS] = 15,
26219a81c14SSteve Longerbeam 	[OV5640_30_FPS] = 30,
263e823fb16SMaxime Ripard 	[OV5640_60_FPS] = 60,
26419a81c14SSteve Longerbeam };
26519a81c14SSteve Longerbeam 
26619a81c14SSteve Longerbeam /* regulator supplies */
26719a81c14SSteve Longerbeam static const char * const ov5640_supply_name[] = {
26841d8d7f5SHugues Fruchet 	"DOVDD", /* Digital I/O (1.8V) supply */
26919a81c14SSteve Longerbeam 	"AVDD",  /* Analog (2.8V) supply */
27024c8ac89SFabio Estevam 	"DVDD",  /* Digital Core (1.5V) supply */
27119a81c14SSteve Longerbeam };
27219a81c14SSteve Longerbeam 
27319a81c14SSteve Longerbeam #define OV5640_NUM_SUPPLIES ARRAY_SIZE(ov5640_supply_name)
27419a81c14SSteve Longerbeam 
27519a81c14SSteve Longerbeam /*
27619a81c14SSteve Longerbeam  * Image size under 1280 * 960 are SUBSAMPLING
27719a81c14SSteve Longerbeam  * Image size upper 1280 * 960 are SCALING
27819a81c14SSteve Longerbeam  */
27919a81c14SSteve Longerbeam enum ov5640_downsize_mode {
28019a81c14SSteve Longerbeam 	SUBSAMPLING,
28119a81c14SSteve Longerbeam 	SCALING,
28219a81c14SSteve Longerbeam };
28319a81c14SSteve Longerbeam 
28419a81c14SSteve Longerbeam struct reg_value {
28519a81c14SSteve Longerbeam 	u16 reg_addr;
28619a81c14SSteve Longerbeam 	u8 val;
28719a81c14SSteve Longerbeam 	u8 mask;
28819a81c14SSteve Longerbeam 	u32 delay_ms;
28919a81c14SSteve Longerbeam };
29019a81c14SSteve Longerbeam 
2915113d5b3SJacopo Mondi struct ov5640_timings {
2923145efcdSJacopo Mondi 	/* Analog crop rectangle. */
2933145efcdSJacopo Mondi 	struct v4l2_rect analog_crop;
2943145efcdSJacopo Mondi 	/* Visibile crop: from analog crop top-left corner. */
2953145efcdSJacopo Mondi 	struct v4l2_rect crop;
2965113d5b3SJacopo Mondi 	/* Total pixels per line: width + fixed hblank. */
297476dec01SMaxime Ripard 	u32 htot;
2985113d5b3SJacopo Mondi 	/* Default vertical blanking: frame height = height + vblank. */
2993145efcdSJacopo Mondi 	u32 vblank_def;
3005113d5b3SJacopo Mondi };
3015113d5b3SJacopo Mondi 
3025113d5b3SJacopo Mondi struct ov5640_mode_info {
3035113d5b3SJacopo Mondi 	enum ov5640_mode_id id;
3045113d5b3SJacopo Mondi 	enum ov5640_downsize_mode dn_mode;
3055113d5b3SJacopo Mondi 	enum ov5640_pixel_rate_id pixel_rate;
3065113d5b3SJacopo Mondi 
3075113d5b3SJacopo Mondi 	unsigned int width;
3085113d5b3SJacopo Mondi 	unsigned int height;
3095113d5b3SJacopo Mondi 
3105113d5b3SJacopo Mondi 	struct ov5640_timings dvp_timings;
3115113d5b3SJacopo Mondi 	struct ov5640_timings csi2_timings;
3125113d5b3SJacopo Mondi 
31319a81c14SSteve Longerbeam 	const struct reg_value *reg_data;
31419a81c14SSteve Longerbeam 	u32 reg_data_size;
3155113d5b3SJacopo Mondi 
3165113d5b3SJacopo Mondi 	/* Used by s_frame_interval only. */
3175554c80eSAdam Ford 	u32 max_fps;
31819a81c14SSteve Longerbeam };
31919a81c14SSteve Longerbeam 
32019a81c14SSteve Longerbeam struct ov5640_ctrls {
32119a81c14SSteve Longerbeam 	struct v4l2_ctrl_handler handler;
322cc196e48SBenoit Parrot 	struct v4l2_ctrl *pixel_rate;
3237a3b8d4bSJacopo Mondi 	struct v4l2_ctrl *link_freq;
32419a81c14SSteve Longerbeam 	struct {
32519a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_exp;
32619a81c14SSteve Longerbeam 		struct v4l2_ctrl *exposure;
32719a81c14SSteve Longerbeam 	};
32819a81c14SSteve Longerbeam 	struct {
32919a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_wb;
33019a81c14SSteve Longerbeam 		struct v4l2_ctrl *blue_balance;
33119a81c14SSteve Longerbeam 		struct v4l2_ctrl *red_balance;
33219a81c14SSteve Longerbeam 	};
33319a81c14SSteve Longerbeam 	struct {
33419a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_gain;
33519a81c14SSteve Longerbeam 		struct v4l2_ctrl *gain;
33619a81c14SSteve Longerbeam 	};
33719a81c14SSteve Longerbeam 	struct v4l2_ctrl *brightness;
3381068fecaSMylène Josserand 	struct v4l2_ctrl *light_freq;
33919a81c14SSteve Longerbeam 	struct v4l2_ctrl *saturation;
34019a81c14SSteve Longerbeam 	struct v4l2_ctrl *contrast;
34119a81c14SSteve Longerbeam 	struct v4l2_ctrl *hue;
34219a81c14SSteve Longerbeam 	struct v4l2_ctrl *test_pattern;
343ce85705aSHugues Fruchet 	struct v4l2_ctrl *hflip;
344ce85705aSHugues Fruchet 	struct v4l2_ctrl *vflip;
34519a81c14SSteve Longerbeam };
34619a81c14SSteve Longerbeam 
34719a81c14SSteve Longerbeam struct ov5640_dev {
34819a81c14SSteve Longerbeam 	struct i2c_client *i2c_client;
34919a81c14SSteve Longerbeam 	struct v4l2_subdev sd;
35019a81c14SSteve Longerbeam 	struct media_pad pad;
35119a81c14SSteve Longerbeam 	struct v4l2_fwnode_endpoint ep; /* the parsed DT endpoint info */
35219a81c14SSteve Longerbeam 	struct clk *xclk; /* system clock to OV5640 */
35319a81c14SSteve Longerbeam 	u32 xclk_freq;
35419a81c14SSteve Longerbeam 
35519a81c14SSteve Longerbeam 	struct regulator_bulk_data supplies[OV5640_NUM_SUPPLIES];
35619a81c14SSteve Longerbeam 	struct gpio_desc *reset_gpio;
35719a81c14SSteve Longerbeam 	struct gpio_desc *pwdn_gpio;
358c3f3ba3eSHugues Fruchet 	bool   upside_down;
35919a81c14SSteve Longerbeam 
36019a81c14SSteve Longerbeam 	/* lock to protect all members below */
36119a81c14SSteve Longerbeam 	struct mutex lock;
36219a81c14SSteve Longerbeam 
36319a81c14SSteve Longerbeam 	int power_count;
36419a81c14SSteve Longerbeam 
36519a81c14SSteve Longerbeam 	struct v4l2_mbus_framefmt fmt;
366fb98e29fSHugues Fruchet 	bool pending_fmt_change;
36719a81c14SSteve Longerbeam 
36819a81c14SSteve Longerbeam 	const struct ov5640_mode_info *current_mode;
369985cdcb0SHugues Fruchet 	const struct ov5640_mode_info *last_mode;
37019a81c14SSteve Longerbeam 	enum ov5640_frame_rate current_fr;
37119a81c14SSteve Longerbeam 	struct v4l2_fract frame_interval;
3723c28588fSJacopo Mondi 	s64 current_link_freq;
37319a81c14SSteve Longerbeam 
37419a81c14SSteve Longerbeam 	struct ov5640_ctrls ctrls;
37519a81c14SSteve Longerbeam 
37619a81c14SSteve Longerbeam 	u32 prev_sysclk, prev_hts;
37719a81c14SSteve Longerbeam 	u32 ae_low, ae_high, ae_target;
37819a81c14SSteve Longerbeam 
37919a81c14SSteve Longerbeam 	bool pending_mode_change;
38019a81c14SSteve Longerbeam 	bool streaming;
38119a81c14SSteve Longerbeam };
38219a81c14SSteve Longerbeam 
38319a81c14SSteve Longerbeam static inline struct ov5640_dev *to_ov5640_dev(struct v4l2_subdev *sd)
38419a81c14SSteve Longerbeam {
38519a81c14SSteve Longerbeam 	return container_of(sd, struct ov5640_dev, sd);
38619a81c14SSteve Longerbeam }
38719a81c14SSteve Longerbeam 
38819a81c14SSteve Longerbeam static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
38919a81c14SSteve Longerbeam {
39019a81c14SSteve Longerbeam 	return &container_of(ctrl->handler, struct ov5640_dev,
39119a81c14SSteve Longerbeam 			     ctrls.handler)->sd;
39219a81c14SSteve Longerbeam }
39319a81c14SSteve Longerbeam 
3948e823f5cSJacopo Mondi static inline bool ov5640_is_csi2(const struct ov5640_dev *sensor)
3958e823f5cSJacopo Mondi {
3968e823f5cSJacopo Mondi 	return sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY;
3978e823f5cSJacopo Mondi }
3988e823f5cSJacopo Mondi 
39919a81c14SSteve Longerbeam /*
40019a81c14SSteve Longerbeam  * FIXME: all of these register tables are likely filled with
40119a81c14SSteve Longerbeam  * entries that set the register to their power-on default values,
40219a81c14SSteve Longerbeam  * and which are otherwise not touched by this driver. Those entries
40319a81c14SSteve Longerbeam  * should be identified and removed to speed register load time
40419a81c14SSteve Longerbeam  * over i2c.
40519a81c14SSteve Longerbeam  */
406fb98e29fSHugues Fruchet /* YUV422 UYVY VGA@30fps */
40719a81c14SSteve Longerbeam static const struct reg_value ov5640_init_setting_30fps_VGA[] = {
40819a81c14SSteve Longerbeam 	{0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0},
409576f5d4bSLad Prabhakar 	{0x3103, 0x03, 0, 0}, {0x3630, 0x36, 0, 0},
41019a81c14SSteve Longerbeam 	{0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0},
41119a81c14SSteve Longerbeam 	{0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0},
41219a81c14SSteve Longerbeam 	{0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0},
41319a81c14SSteve Longerbeam 	{0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, {0x3906, 0x10, 0, 0},
41419a81c14SSteve Longerbeam 	{0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, {0x3600, 0x08, 0, 0},
41519a81c14SSteve Longerbeam 	{0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, {0x3620, 0x52, 0, 0},
41619a81c14SSteve Longerbeam 	{0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, {0x3a13, 0x43, 0, 0},
41719a81c14SSteve Longerbeam 	{0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3635, 0x13, 0, 0},
41819a81c14SSteve Longerbeam 	{0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, {0x3622, 0x01, 0, 0},
41919a81c14SSteve Longerbeam 	{0x3c01, 0xa4, 0, 0}, {0x3c04, 0x28, 0, 0}, {0x3c05, 0x98, 0, 0},
42019a81c14SSteve Longerbeam 	{0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0},
42119a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
42219a81c14SSteve Longerbeam 	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
4233145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
42419a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
42519a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
42619a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
42719a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
42819a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
42919a81c14SSteve Longerbeam 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0},
43019a81c14SSteve Longerbeam 	{0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0},
431aa4bb8b8SJacopo Mondi 	{0x302e, 0x08, 0, 0}, {0x4300, 0x3f, 0, 0},
4322b5c18f9SChen-Yu Tsai 	{0x501f, 0x00, 0, 0}, {0x4407, 0x04, 0, 0},
43319a81c14SSteve Longerbeam 	{0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
434aa4bb8b8SJacopo Mondi 	{0x4837, 0x0a, 0, 0}, {0x3824, 0x02, 0, 0},
43519a81c14SSteve Longerbeam 	{0x5000, 0xa7, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0},
43619a81c14SSteve Longerbeam 	{0x5181, 0xf2, 0, 0}, {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0},
43719a81c14SSteve Longerbeam 	{0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0},
43819a81c14SSteve Longerbeam 	{0x5187, 0x09, 0, 0}, {0x5188, 0x09, 0, 0}, {0x5189, 0x88, 0, 0},
43919a81c14SSteve Longerbeam 	{0x518a, 0x54, 0, 0}, {0x518b, 0xee, 0, 0}, {0x518c, 0xb2, 0, 0},
44019a81c14SSteve Longerbeam 	{0x518d, 0x50, 0, 0}, {0x518e, 0x34, 0, 0}, {0x518f, 0x6b, 0, 0},
44119a81c14SSteve Longerbeam 	{0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0},
44219a81c14SSteve Longerbeam 	{0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0},
44319a81c14SSteve Longerbeam 	{0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0},
44419a81c14SSteve Longerbeam 	{0x5199, 0x6c, 0, 0}, {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0},
44519a81c14SSteve Longerbeam 	{0x519c, 0x09, 0, 0}, {0x519d, 0x2b, 0, 0}, {0x519e, 0x38, 0, 0},
44619a81c14SSteve Longerbeam 	{0x5381, 0x1e, 0, 0}, {0x5382, 0x5b, 0, 0}, {0x5383, 0x08, 0, 0},
44719a81c14SSteve Longerbeam 	{0x5384, 0x0a, 0, 0}, {0x5385, 0x7e, 0, 0}, {0x5386, 0x88, 0, 0},
44819a81c14SSteve Longerbeam 	{0x5387, 0x7c, 0, 0}, {0x5388, 0x6c, 0, 0}, {0x5389, 0x10, 0, 0},
44919a81c14SSteve Longerbeam 	{0x538a, 0x01, 0, 0}, {0x538b, 0x98, 0, 0}, {0x5300, 0x08, 0, 0},
45019a81c14SSteve Longerbeam 	{0x5301, 0x30, 0, 0}, {0x5302, 0x10, 0, 0}, {0x5303, 0x00, 0, 0},
45119a81c14SSteve Longerbeam 	{0x5304, 0x08, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x08, 0, 0},
45219a81c14SSteve Longerbeam 	{0x5307, 0x16, 0, 0}, {0x5309, 0x08, 0, 0}, {0x530a, 0x30, 0, 0},
45319a81c14SSteve Longerbeam 	{0x530b, 0x04, 0, 0}, {0x530c, 0x06, 0, 0}, {0x5480, 0x01, 0, 0},
45419a81c14SSteve Longerbeam 	{0x5481, 0x08, 0, 0}, {0x5482, 0x14, 0, 0}, {0x5483, 0x28, 0, 0},
45519a81c14SSteve Longerbeam 	{0x5484, 0x51, 0, 0}, {0x5485, 0x65, 0, 0}, {0x5486, 0x71, 0, 0},
45619a81c14SSteve Longerbeam 	{0x5487, 0x7d, 0, 0}, {0x5488, 0x87, 0, 0}, {0x5489, 0x91, 0, 0},
45719a81c14SSteve Longerbeam 	{0x548a, 0x9a, 0, 0}, {0x548b, 0xaa, 0, 0}, {0x548c, 0xb8, 0, 0},
45819a81c14SSteve Longerbeam 	{0x548d, 0xcd, 0, 0}, {0x548e, 0xdd, 0, 0}, {0x548f, 0xea, 0, 0},
45919a81c14SSteve Longerbeam 	{0x5490, 0x1d, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5583, 0x40, 0, 0},
46019a81c14SSteve Longerbeam 	{0x5584, 0x10, 0, 0}, {0x5589, 0x10, 0, 0}, {0x558a, 0x00, 0, 0},
46119a81c14SSteve Longerbeam 	{0x558b, 0xf8, 0, 0}, {0x5800, 0x23, 0, 0}, {0x5801, 0x14, 0, 0},
46219a81c14SSteve Longerbeam 	{0x5802, 0x0f, 0, 0}, {0x5803, 0x0f, 0, 0}, {0x5804, 0x12, 0, 0},
46319a81c14SSteve Longerbeam 	{0x5805, 0x26, 0, 0}, {0x5806, 0x0c, 0, 0}, {0x5807, 0x08, 0, 0},
46419a81c14SSteve Longerbeam 	{0x5808, 0x05, 0, 0}, {0x5809, 0x05, 0, 0}, {0x580a, 0x08, 0, 0},
46519a81c14SSteve Longerbeam 	{0x580b, 0x0d, 0, 0}, {0x580c, 0x08, 0, 0}, {0x580d, 0x03, 0, 0},
46619a81c14SSteve Longerbeam 	{0x580e, 0x00, 0, 0}, {0x580f, 0x00, 0, 0}, {0x5810, 0x03, 0, 0},
46719a81c14SSteve Longerbeam 	{0x5811, 0x09, 0, 0}, {0x5812, 0x07, 0, 0}, {0x5813, 0x03, 0, 0},
46819a81c14SSteve Longerbeam 	{0x5814, 0x00, 0, 0}, {0x5815, 0x01, 0, 0}, {0x5816, 0x03, 0, 0},
46919a81c14SSteve Longerbeam 	{0x5817, 0x08, 0, 0}, {0x5818, 0x0d, 0, 0}, {0x5819, 0x08, 0, 0},
47019a81c14SSteve Longerbeam 	{0x581a, 0x05, 0, 0}, {0x581b, 0x06, 0, 0}, {0x581c, 0x08, 0, 0},
47119a81c14SSteve Longerbeam 	{0x581d, 0x0e, 0, 0}, {0x581e, 0x29, 0, 0}, {0x581f, 0x17, 0, 0},
47219a81c14SSteve Longerbeam 	{0x5820, 0x11, 0, 0}, {0x5821, 0x11, 0, 0}, {0x5822, 0x15, 0, 0},
47319a81c14SSteve Longerbeam 	{0x5823, 0x28, 0, 0}, {0x5824, 0x46, 0, 0}, {0x5825, 0x26, 0, 0},
47419a81c14SSteve Longerbeam 	{0x5826, 0x08, 0, 0}, {0x5827, 0x26, 0, 0}, {0x5828, 0x64, 0, 0},
47519a81c14SSteve Longerbeam 	{0x5829, 0x26, 0, 0}, {0x582a, 0x24, 0, 0}, {0x582b, 0x22, 0, 0},
47619a81c14SSteve Longerbeam 	{0x582c, 0x24, 0, 0}, {0x582d, 0x24, 0, 0}, {0x582e, 0x06, 0, 0},
47719a81c14SSteve Longerbeam 	{0x582f, 0x22, 0, 0}, {0x5830, 0x40, 0, 0}, {0x5831, 0x42, 0, 0},
47819a81c14SSteve Longerbeam 	{0x5832, 0x24, 0, 0}, {0x5833, 0x26, 0, 0}, {0x5834, 0x24, 0, 0},
47919a81c14SSteve Longerbeam 	{0x5835, 0x22, 0, 0}, {0x5836, 0x22, 0, 0}, {0x5837, 0x26, 0, 0},
48019a81c14SSteve Longerbeam 	{0x5838, 0x44, 0, 0}, {0x5839, 0x24, 0, 0}, {0x583a, 0x26, 0, 0},
48119a81c14SSteve Longerbeam 	{0x583b, 0x28, 0, 0}, {0x583c, 0x42, 0, 0}, {0x583d, 0xce, 0, 0},
48219a81c14SSteve Longerbeam 	{0x5025, 0x00, 0, 0}, {0x3a0f, 0x30, 0, 0}, {0x3a10, 0x28, 0, 0},
48319a81c14SSteve Longerbeam 	{0x3a1b, 0x30, 0, 0}, {0x3a1e, 0x26, 0, 0}, {0x3a11, 0x60, 0, 0},
48419a81c14SSteve Longerbeam 	{0x3a1f, 0x14, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3c00, 0x04, 0, 300},
48519a81c14SSteve Longerbeam };
48619a81c14SSteve Longerbeam 
487*db15c195SJacopo Mondi static const struct reg_value ov5640_setting_low_res[] = {
488c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
48919a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
490ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
4913145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
49219a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
49319a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
49419a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
49519a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
49619a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
4972b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
498e15197bdSJacopo Mondi 	{0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0},
49919a81c14SSteve Longerbeam };
50019a81c14SSteve Longerbeam 
501086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_720P_1280_720[] = {
502c14d107eSMaxime Ripard 	{0x3c07, 0x07, 0, 0},
50319a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
504ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
5053145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
50619a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
50719a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0},
50819a81c14SSteve Longerbeam 	{0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0},
50919a81c14SSteve Longerbeam 	{0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0},
51019a81c14SSteve Longerbeam 	{0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0},
5112b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
51219a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
51319a81c14SSteve Longerbeam 	{0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0},
51419a81c14SSteve Longerbeam };
51519a81c14SSteve Longerbeam 
516086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_1080P_1920_1080[] = {
517c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
51819a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
519ce85705aSHugues Fruchet 	{0x3814, 0x11, 0, 0},
5203145efcdSJacopo Mondi 	{0x3815, 0x11, 0, 0},
52119a81c14SSteve Longerbeam 	{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
52219a81c14SSteve Longerbeam 	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
52319a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
52419a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
52519a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5262b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0},
52719a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
528c14d107eSMaxime Ripard 	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0},
529c14d107eSMaxime Ripard 	{0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0},
53019a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
531476dec01SMaxime Ripard 	{0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0},
53219a81c14SSteve Longerbeam 	{0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0},
53319a81c14SSteve Longerbeam 	{0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0},
53419a81c14SSteve Longerbeam 	{0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0},
5352b5c18f9SChen-Yu Tsai 	{0x3a15, 0x60, 0, 0}, {0x4407, 0x04, 0, 0},
53619a81c14SSteve Longerbeam 	{0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0},
53792b9096cSBenoit Parrot 	{0x4005, 0x1a, 0, 0},
53819a81c14SSteve Longerbeam };
53919a81c14SSteve Longerbeam 
540086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_QSXGA_2592_1944[] = {
541c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
54219a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
543ce85705aSHugues Fruchet 	{0x3814, 0x11, 0, 0},
5443145efcdSJacopo Mondi 	{0x3815, 0x11, 0, 0},
54519a81c14SSteve Longerbeam 	{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
54619a81c14SSteve Longerbeam 	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
54719a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
54819a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
54919a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5502b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0},
55119a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
55219a81c14SSteve Longerbeam 	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70},
55319a81c14SSteve Longerbeam };
55419a81c14SSteve Longerbeam 
55519a81c14SSteve Longerbeam /* power-on sensor init reg table */
55619a81c14SSteve Longerbeam static const struct ov5640_mode_info ov5640_mode_init_data = {
5573145efcdSJacopo Mondi 		.id		= 0,
5583145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
5593145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
5605113d5b3SJacopo Mondi 		.width	= 640,
5615113d5b3SJacopo Mondi 		.height	= 480,
5625113d5b3SJacopo Mondi 		.dvp_timings = {
5633145efcdSJacopo Mondi 			.analog_crop = {
5643145efcdSJacopo Mondi 				.left	= 0,
5653145efcdSJacopo Mondi 				.top	= 4,
5663145efcdSJacopo Mondi 				.width	= 2624,
5673145efcdSJacopo Mondi 				.height	= 1944,
5683145efcdSJacopo Mondi 			},
5693145efcdSJacopo Mondi 			.crop = {
5703145efcdSJacopo Mondi 				.left	= 16,
5713145efcdSJacopo Mondi 				.top	= 6,
5723145efcdSJacopo Mondi 				.width	= 640,
5733145efcdSJacopo Mondi 				.height	= 480,
5743145efcdSJacopo Mondi 			},
5753145efcdSJacopo Mondi 			.htot		= 1896,
5763145efcdSJacopo Mondi 			.vblank_def	= 504,
5775113d5b3SJacopo Mondi 		},
5785113d5b3SJacopo Mondi 		.csi2_timings = {
5795113d5b3SJacopo Mondi 			.analog_crop = {
5805113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
5815113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
5825113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
5835113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
5845113d5b3SJacopo Mondi 			},
5855113d5b3SJacopo Mondi 			.crop = {
5865113d5b3SJacopo Mondi 				.left	= 2,
5875113d5b3SJacopo Mondi 				.top	= 4,
5885113d5b3SJacopo Mondi 				.width	= 640,
5895113d5b3SJacopo Mondi 				.height	= 480,
5905113d5b3SJacopo Mondi 			},
5915113d5b3SJacopo Mondi 			.htot		= 1896,
5925113d5b3SJacopo Mondi 			.vblank_def	= 504,
5935113d5b3SJacopo Mondi 		},
5943145efcdSJacopo Mondi 		.reg_data	= ov5640_init_setting_30fps_VGA,
5953145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_init_setting_30fps_VGA),
5963145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
59719a81c14SSteve Longerbeam };
59819a81c14SSteve Longerbeam 
5995113d5b3SJacopo Mondi static const struct ov5640_mode_info ov5640_mode_data[OV5640_NUM_MODES] = {
6008409d017SJacopo Mondi 	{
6018409d017SJacopo Mondi 		/* 160x120 */
6023145efcdSJacopo Mondi 		.id		= OV5640_MODE_QQVGA_160_120,
6033145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
6043145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
6055113d5b3SJacopo Mondi 		.width		= 160,
6065113d5b3SJacopo Mondi 		.height		= 120,
6075113d5b3SJacopo Mondi 		.dvp_timings = {
6083145efcdSJacopo Mondi 			.analog_crop = {
6093145efcdSJacopo Mondi 				.left	= 0,
6103145efcdSJacopo Mondi 				.top	= 4,
6113145efcdSJacopo Mondi 				.width	= 2624,
6123145efcdSJacopo Mondi 				.height	= 1944,
6133145efcdSJacopo Mondi 			},
6143145efcdSJacopo Mondi 			.crop = {
6153145efcdSJacopo Mondi 				.left	= 16,
6163145efcdSJacopo Mondi 				.top	= 6,
6173145efcdSJacopo Mondi 				.width	= 160,
6183145efcdSJacopo Mondi 				.height	= 120,
6193145efcdSJacopo Mondi 			},
6203145efcdSJacopo Mondi 			.htot		= 1896,
6213145efcdSJacopo Mondi 			.vblank_def	= 864,
6225113d5b3SJacopo Mondi 		},
6235113d5b3SJacopo Mondi 		.csi2_timings = {
6245113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
6255113d5b3SJacopo Mondi 			.analog_crop = {
6265113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
6275113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
6285113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
6295113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
6305113d5b3SJacopo Mondi 			},
6315113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
6325113d5b3SJacopo Mondi 			.crop = {
6335113d5b3SJacopo Mondi 				.left	= 2,
6345113d5b3SJacopo Mondi 				.top	= 4,
6355113d5b3SJacopo Mondi 				.width	= 160,
6365113d5b3SJacopo Mondi 				.height	= 120,
6375113d5b3SJacopo Mondi 			},
6385113d5b3SJacopo Mondi 			.htot		= 1896,
6395113d5b3SJacopo Mondi 			.vblank_def	= 864,
6405113d5b3SJacopo Mondi 		},
641*db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
642*db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
6433145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
6448409d017SJacopo Mondi 	}, {
6458409d017SJacopo Mondi 		/* 176x144 */
6463145efcdSJacopo Mondi 		.id		= OV5640_MODE_QCIF_176_144,
6473145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
6483145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
6495113d5b3SJacopo Mondi 		.width		= 176,
6505113d5b3SJacopo Mondi 		.height		= 144,
6515113d5b3SJacopo Mondi 		.dvp_timings = {
6523145efcdSJacopo Mondi 			.analog_crop = {
6533145efcdSJacopo Mondi 				.left	= 0,
6543145efcdSJacopo Mondi 				.top	= 4,
6553145efcdSJacopo Mondi 				.width	= 2624,
6563145efcdSJacopo Mondi 				.height	= 1944,
6573145efcdSJacopo Mondi 			},
6583145efcdSJacopo Mondi 			.crop = {
6593145efcdSJacopo Mondi 				.left	= 16,
6603145efcdSJacopo Mondi 				.top	= 6,
6613145efcdSJacopo Mondi 				.width	= 176,
6623145efcdSJacopo Mondi 				.height	= 144,
6633145efcdSJacopo Mondi 			},
6643145efcdSJacopo Mondi 			.htot		= 1896,
6653145efcdSJacopo Mondi 			.vblank_def	= 840,
6665113d5b3SJacopo Mondi 		},
6675113d5b3SJacopo Mondi 		.csi2_timings = {
6685113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
6695113d5b3SJacopo Mondi 			.analog_crop = {
6705113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
6715113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
6725113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
6735113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
6745113d5b3SJacopo Mondi 			},
6755113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
6765113d5b3SJacopo Mondi 			.crop = {
6775113d5b3SJacopo Mondi 				.left	= 2,
6785113d5b3SJacopo Mondi 				.top	= 4,
6795113d5b3SJacopo Mondi 				.width	= 176,
6805113d5b3SJacopo Mondi 				.height	= 144,
6815113d5b3SJacopo Mondi 			},
6825113d5b3SJacopo Mondi 			.htot		= 1896,
6835113d5b3SJacopo Mondi 			.vblank_def	= 840,
6845113d5b3SJacopo Mondi 		},
685*db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
686*db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
6873145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
6888409d017SJacopo Mondi 	}, {
6898409d017SJacopo Mondi 		/* 320x240 */
6903145efcdSJacopo Mondi 		.id		= OV5640_MODE_QVGA_320_240,
6913145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
6925113d5b3SJacopo Mondi 		.width		= 320,
6935113d5b3SJacopo Mondi 		.height		= 240,
6943145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
6955113d5b3SJacopo Mondi 		.dvp_timings = {
6963145efcdSJacopo Mondi 			.analog_crop = {
6973145efcdSJacopo Mondi 				.left	= 0,
6983145efcdSJacopo Mondi 				.top	= 4,
6993145efcdSJacopo Mondi 				.width	= 2624,
7003145efcdSJacopo Mondi 				.height	= 1944,
7013145efcdSJacopo Mondi 			},
7023145efcdSJacopo Mondi 			.crop = {
7033145efcdSJacopo Mondi 				.left	= 16,
7043145efcdSJacopo Mondi 				.top	= 6,
7053145efcdSJacopo Mondi 				.width	= 320,
7063145efcdSJacopo Mondi 				.height	= 240,
7073145efcdSJacopo Mondi 			},
7083145efcdSJacopo Mondi 			.htot		= 1896,
7093145efcdSJacopo Mondi 			.vblank_def	= 744,
7105113d5b3SJacopo Mondi 		},
7115113d5b3SJacopo Mondi 		.csi2_timings = {
7125113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
7135113d5b3SJacopo Mondi 			.analog_crop = {
7145113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
7155113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
7165113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
7175113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
7185113d5b3SJacopo Mondi 			},
7195113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
7205113d5b3SJacopo Mondi 			.crop = {
7215113d5b3SJacopo Mondi 				.left	= 2,
7225113d5b3SJacopo Mondi 				.top	= 4,
7235113d5b3SJacopo Mondi 				.width	= 320,
7245113d5b3SJacopo Mondi 				.height	= 240,
7255113d5b3SJacopo Mondi 			},
7265113d5b3SJacopo Mondi 			.htot		= 1896,
7275113d5b3SJacopo Mondi 			.vblank_def	= 744,
7285113d5b3SJacopo Mondi 		},
729*db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
730*db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
7313145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
7328409d017SJacopo Mondi 	}, {
7338409d017SJacopo Mondi 		/* 640x480 */
7343145efcdSJacopo Mondi 		.id		= OV5640_MODE_VGA_640_480,
7353145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
7363145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
7375113d5b3SJacopo Mondi 		.width		= 640,
7385113d5b3SJacopo Mondi 		.height		= 480,
7395113d5b3SJacopo Mondi 		.dvp_timings = {
7403145efcdSJacopo Mondi 			.analog_crop = {
7413145efcdSJacopo Mondi 				.left	= 0,
7423145efcdSJacopo Mondi 				.top	= 4,
7433145efcdSJacopo Mondi 				.width	= 2624,
7443145efcdSJacopo Mondi 				.height	= 1944,
7453145efcdSJacopo Mondi 			},
7463145efcdSJacopo Mondi 			.crop = {
7473145efcdSJacopo Mondi 				.left	= 16,
7483145efcdSJacopo Mondi 				.top	= 6,
7493145efcdSJacopo Mondi 				.width	= 640,
7503145efcdSJacopo Mondi 				.height	= 480,
7513145efcdSJacopo Mondi 			},
7523145efcdSJacopo Mondi 			.htot		= 1896,
7533145efcdSJacopo Mondi 			.vblank_def	= 600,
7545113d5b3SJacopo Mondi 		},
7555113d5b3SJacopo Mondi 		.csi2_timings = {
7565113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
7575113d5b3SJacopo Mondi 			.analog_crop = {
7585113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
7595113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
7605113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
7615113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
7625113d5b3SJacopo Mondi 			},
7635113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
7645113d5b3SJacopo Mondi 			.crop = {
7655113d5b3SJacopo Mondi 				.left	= 2,
7665113d5b3SJacopo Mondi 				.top	= 4,
7675113d5b3SJacopo Mondi 				.width	= 640,
7685113d5b3SJacopo Mondi 				.height	= 480,
7695113d5b3SJacopo Mondi 			},
7705113d5b3SJacopo Mondi 			.htot		= 1896,
7715113d5b3SJacopo Mondi 			.vblank_def	= 600,
7725113d5b3SJacopo Mondi 		},
773*db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
774*db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
7753145efcdSJacopo Mondi 		.max_fps	= OV5640_60_FPS
7768409d017SJacopo Mondi 	}, {
7778409d017SJacopo Mondi 		/* 720x480 */
7783145efcdSJacopo Mondi 		.id		= OV5640_MODE_NTSC_720_480,
7793145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
7805113d5b3SJacopo Mondi 		.width		= 720,
7815113d5b3SJacopo Mondi 		.height		= 480,
7823145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
7835113d5b3SJacopo Mondi 		.dvp_timings = {
7843145efcdSJacopo Mondi 			.analog_crop = {
7853145efcdSJacopo Mondi 				.left	= 0,
7863145efcdSJacopo Mondi 				.top	= 4,
7873145efcdSJacopo Mondi 				.width	= 2624,
7883145efcdSJacopo Mondi 				.height	= 1944,
7893145efcdSJacopo Mondi 			},
7903145efcdSJacopo Mondi 			.crop = {
791e74ef55bSJacopo Mondi 				.left	= 56,
7923145efcdSJacopo Mondi 				.top	= 60,
7933145efcdSJacopo Mondi 				.width	= 720,
7943145efcdSJacopo Mondi 				.height	= 480,
7953145efcdSJacopo Mondi 			},
7963145efcdSJacopo Mondi 			.htot		= 1896,
7973145efcdSJacopo Mondi 			.vblank_def	= 504,
7985113d5b3SJacopo Mondi 		},
7995113d5b3SJacopo Mondi 		.csi2_timings = {
8005113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
8015113d5b3SJacopo Mondi 			.analog_crop = {
8025113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
8035113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
8045113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
8055113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
8065113d5b3SJacopo Mondi 			},
8075113d5b3SJacopo Mondi 			.crop = {
8085113d5b3SJacopo Mondi 				.left	= 56,
8095113d5b3SJacopo Mondi 				.top	= 60,
8105113d5b3SJacopo Mondi 				.width	= 720,
8115113d5b3SJacopo Mondi 				.height	= 480,
8125113d5b3SJacopo Mondi 			},
8135113d5b3SJacopo Mondi 			.htot		= 1896,
8145113d5b3SJacopo Mondi 			.vblank_def	= 504,
8155113d5b3SJacopo Mondi 		},
816*db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
817*db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
8183145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
8198409d017SJacopo Mondi 	}, {
8208409d017SJacopo Mondi 		/* 720x576 */
8213145efcdSJacopo Mondi 		.id		= OV5640_MODE_PAL_720_576,
8223145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
8235113d5b3SJacopo Mondi 		.width		= 720,
8245113d5b3SJacopo Mondi 		.height		= 576,
8253145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
8265113d5b3SJacopo Mondi 		.dvp_timings = {
8273145efcdSJacopo Mondi 			.analog_crop = {
8283145efcdSJacopo Mondi 				.left	= 0,
8293145efcdSJacopo Mondi 				.top	= 4,
8303145efcdSJacopo Mondi 				.width	= 2624,
8313145efcdSJacopo Mondi 				.height	= 1944,
8323145efcdSJacopo Mondi 			},
8333145efcdSJacopo Mondi 			.crop = {
8343145efcdSJacopo Mondi 				.left	= 56,
8353145efcdSJacopo Mondi 				.top	= 6,
8363145efcdSJacopo Mondi 				.width	= 720,
8373145efcdSJacopo Mondi 				.height	= 576,
8383145efcdSJacopo Mondi 			},
8393145efcdSJacopo Mondi 			.htot		= 1896,
8403145efcdSJacopo Mondi 			.vblank_def	= 408,
8415113d5b3SJacopo Mondi 		},
8425113d5b3SJacopo Mondi 		.csi2_timings = {
8435113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
8445113d5b3SJacopo Mondi 			.analog_crop = {
8455113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
8465113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
8475113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
8485113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
8495113d5b3SJacopo Mondi 			},
8505113d5b3SJacopo Mondi 			.crop = {
8515113d5b3SJacopo Mondi 				.left	= 56,
8525113d5b3SJacopo Mondi 				.top	= 6,
8535113d5b3SJacopo Mondi 				.width	= 720,
8545113d5b3SJacopo Mondi 				.height	= 576,
8555113d5b3SJacopo Mondi 			},
8565113d5b3SJacopo Mondi 			.htot		= 1896,
8575113d5b3SJacopo Mondi 			.vblank_def	= 408,
8585113d5b3SJacopo Mondi 		},
859*db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
860*db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
8613145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
8628409d017SJacopo Mondi 	}, {
8638409d017SJacopo Mondi 		/* 1024x768 */
8643145efcdSJacopo Mondi 		.id		= OV5640_MODE_XGA_1024_768,
8653145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
8663145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
8675113d5b3SJacopo Mondi 		.width		= 1024,
8685113d5b3SJacopo Mondi 		.height		= 768,
8695113d5b3SJacopo Mondi 		.dvp_timings = {
8703145efcdSJacopo Mondi 			.analog_crop = {
8713145efcdSJacopo Mondi 				.left	= 0,
8723145efcdSJacopo Mondi 				.top	= 4,
8733145efcdSJacopo Mondi 				.width	= 2624,
8743145efcdSJacopo Mondi 				.height	= 1944,
8753145efcdSJacopo Mondi 			},
8763145efcdSJacopo Mondi 			.crop = {
8773145efcdSJacopo Mondi 				.left	= 16,
8783145efcdSJacopo Mondi 				.top	= 6,
8793145efcdSJacopo Mondi 				.width	= 1024,
8803145efcdSJacopo Mondi 				.height	= 768,
8813145efcdSJacopo Mondi 			},
8823145efcdSJacopo Mondi 			.htot		= 1896,
8833145efcdSJacopo Mondi 			.vblank_def	= 312,
8845113d5b3SJacopo Mondi 		},
8855113d5b3SJacopo Mondi 		.csi2_timings = {
8865113d5b3SJacopo Mondi 			.analog_crop = {
8875113d5b3SJacopo Mondi 				.left	= 0,
8885113d5b3SJacopo Mondi 				.top	= 4,
8895113d5b3SJacopo Mondi 				.width	= OV5640_NATIVE_WIDTH,
8905113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
8915113d5b3SJacopo Mondi 			},
8925113d5b3SJacopo Mondi 			.crop = {
8935113d5b3SJacopo Mondi 				.left	= 16,
8945113d5b3SJacopo Mondi 				.top	= 6,
8955113d5b3SJacopo Mondi 				.width	= 1024,
8965113d5b3SJacopo Mondi 				.height	= 768,
8975113d5b3SJacopo Mondi 			},
8985113d5b3SJacopo Mondi 			.htot		= 1896,
8995113d5b3SJacopo Mondi 			.vblank_def	= 312,
9005113d5b3SJacopo Mondi 		},
901*db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
902*db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
9033145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
9048409d017SJacopo Mondi 	}, {
9058409d017SJacopo Mondi 		/* 1280x720 */
9063145efcdSJacopo Mondi 		.id		= OV5640_MODE_720P_1280_720,
9073145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
9083145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_124M,
9095113d5b3SJacopo Mondi 		.width		= 1280,
9105113d5b3SJacopo Mondi 		.height		= 720,
9115113d5b3SJacopo Mondi 		.dvp_timings = {
9123145efcdSJacopo Mondi 			.analog_crop = {
9133145efcdSJacopo Mondi 				.left	= 0,
9143145efcdSJacopo Mondi 				.top	= 250,
9153145efcdSJacopo Mondi 				.width	= 2624,
9163145efcdSJacopo Mondi 				.height	= 1456,
9173145efcdSJacopo Mondi 			},
9183145efcdSJacopo Mondi 			.crop = {
9193145efcdSJacopo Mondi 				.left	= 16,
9203145efcdSJacopo Mondi 				.top	= 4,
9213145efcdSJacopo Mondi 				.width	= 1280,
9223145efcdSJacopo Mondi 				.height	= 720,
9233145efcdSJacopo Mondi 			},
9243145efcdSJacopo Mondi 			.htot		= 1892,
9253145efcdSJacopo Mondi 			.vblank_def	= 20,
9265113d5b3SJacopo Mondi 		},
9275113d5b3SJacopo Mondi 		.csi2_timings = {
9285113d5b3SJacopo Mondi 			.analog_crop = {
9295113d5b3SJacopo Mondi 				.left	= 0,
9305113d5b3SJacopo Mondi 				.top	= 250,
9315113d5b3SJacopo Mondi 				.width	= 2624,
9325113d5b3SJacopo Mondi 				.height	= 1456,
9335113d5b3SJacopo Mondi 			},
9345113d5b3SJacopo Mondi 			.crop = {
9355113d5b3SJacopo Mondi 				.left	= 16,
9365113d5b3SJacopo Mondi 				.top	= 4,
9375113d5b3SJacopo Mondi 				.width	= 1280,
9385113d5b3SJacopo Mondi 				.height	= 720,
9395113d5b3SJacopo Mondi 			},
9405113d5b3SJacopo Mondi 			.htot		= 1892,
9415113d5b3SJacopo Mondi 			.vblank_def	= 20,
9425113d5b3SJacopo Mondi 		},
9433145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_720P_1280_720,
9443145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_720P_1280_720),
9453145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
9468409d017SJacopo Mondi 	}, {
9478409d017SJacopo Mondi 		/* 1920x1080 */
9483145efcdSJacopo Mondi 		.id		= OV5640_MODE_1080P_1920_1080,
9493145efcdSJacopo Mondi 		.dn_mode	= SCALING,
9503145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_148M,
9515113d5b3SJacopo Mondi 		.width		= 1920,
9525113d5b3SJacopo Mondi 		.height		= 1080,
9535113d5b3SJacopo Mondi 		.dvp_timings = {
9543145efcdSJacopo Mondi 			.analog_crop = {
9553145efcdSJacopo Mondi 				.left	= 336,
9563145efcdSJacopo Mondi 				.top	= 434,
9573145efcdSJacopo Mondi 				.width	= 1952,
9583145efcdSJacopo Mondi 				.height	= 1088,
9593145efcdSJacopo Mondi 			},
9603145efcdSJacopo Mondi 			.crop = {
9613145efcdSJacopo Mondi 				.left	= 16,
9623145efcdSJacopo Mondi 				.top	= 4,
9633145efcdSJacopo Mondi 				.width	= 1920,
9643145efcdSJacopo Mondi 				.height	= 1080,
9653145efcdSJacopo Mondi 			},
9663145efcdSJacopo Mondi 			.htot		= 2500,
9673145efcdSJacopo Mondi 			.vblank_def	= 40,
9685113d5b3SJacopo Mondi 		},
9695113d5b3SJacopo Mondi 		.csi2_timings = {
9705113d5b3SJacopo Mondi 			/* Crop the full valid pixel array in the center. */
9715113d5b3SJacopo Mondi 			.analog_crop = {
9725113d5b3SJacopo Mondi 				.left	= 336,
9735113d5b3SJacopo Mondi 				.top	= 434,
9745113d5b3SJacopo Mondi 				.width	= 1952,
9755113d5b3SJacopo Mondi 				.height	= 1088,
9765113d5b3SJacopo Mondi 			},
9775113d5b3SJacopo Mondi 			/* Maintain a larger processing margins. */
9785113d5b3SJacopo Mondi 			.crop = {
9795113d5b3SJacopo Mondi 				.left	= 16,
9805113d5b3SJacopo Mondi 				.top	= 4,
9815113d5b3SJacopo Mondi 				.width	= 1920,
9825113d5b3SJacopo Mondi 				.height	= 1080,
9835113d5b3SJacopo Mondi 			},
9845113d5b3SJacopo Mondi 			.htot		= 2500,
9855113d5b3SJacopo Mondi 			.vblank_def	= 40,
9865113d5b3SJacopo Mondi 		},
9873145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_1080P_1920_1080,
9883145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_1080P_1920_1080),
9893145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
9908409d017SJacopo Mondi 	}, {
9918409d017SJacopo Mondi 		/* 2592x1944 */
9923145efcdSJacopo Mondi 		.id		= OV5640_MODE_QSXGA_2592_1944,
9933145efcdSJacopo Mondi 		.dn_mode	= SCALING,
9943145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_168M,
9955113d5b3SJacopo Mondi 		.width		= OV5640_PIXEL_ARRAY_WIDTH,
9965113d5b3SJacopo Mondi 		.height		= OV5640_PIXEL_ARRAY_HEIGHT,
9975113d5b3SJacopo Mondi 		.dvp_timings = {
9983145efcdSJacopo Mondi 			.analog_crop = {
9993145efcdSJacopo Mondi 				.left	= 0,
10003145efcdSJacopo Mondi 				.top	= 0,
10013145efcdSJacopo Mondi 				.width	= 2624,
10023145efcdSJacopo Mondi 				.height	= 1952,
10033145efcdSJacopo Mondi 			},
10043145efcdSJacopo Mondi 			.crop = {
10053145efcdSJacopo Mondi 				.left	= 16,
10063145efcdSJacopo Mondi 				.top	= 4,
10073145efcdSJacopo Mondi 				.width	= 2592,
10083145efcdSJacopo Mondi 				.height	= 1944,
10093145efcdSJacopo Mondi 			},
10103145efcdSJacopo Mondi 			.htot		= 2844,
10113145efcdSJacopo Mondi 			.vblank_def	= 24,
10125113d5b3SJacopo Mondi 		},
10135113d5b3SJacopo Mondi 		.csi2_timings = {
10145113d5b3SJacopo Mondi 			/* Give more processing margin to full resolution. */
10155113d5b3SJacopo Mondi 			.analog_crop = {
10165113d5b3SJacopo Mondi 				.left	= 0,
10175113d5b3SJacopo Mondi 				.top	= 0,
10185113d5b3SJacopo Mondi 				.width	= OV5640_NATIVE_WIDTH,
10195113d5b3SJacopo Mondi 				.height	= 1952,
10205113d5b3SJacopo Mondi 			},
10215113d5b3SJacopo Mondi 			.crop = {
10225113d5b3SJacopo Mondi 				.left	= 16,
10235113d5b3SJacopo Mondi 				.top	= 4,
10245113d5b3SJacopo Mondi 				.width	= 2592,
10255113d5b3SJacopo Mondi 				.height	= 1944,
10265113d5b3SJacopo Mondi 			},
10275113d5b3SJacopo Mondi 			.htot		= 2844,
10285113d5b3SJacopo Mondi 			.vblank_def	= 24,
10295113d5b3SJacopo Mondi 		},
10303145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_QSXGA_2592_1944,
10313145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_QSXGA_2592_1944),
10323145efcdSJacopo Mondi 		.max_fps	= OV5640_15_FPS
10338409d017SJacopo Mondi 	},
103419a81c14SSteve Longerbeam };
103519a81c14SSteve Longerbeam 
10362de6bb97SJacopo Mondi static const struct ov5640_timings *
10372de6bb97SJacopo Mondi ov5640_timings(const struct ov5640_dev *sensor,
10382de6bb97SJacopo Mondi 	       const struct ov5640_mode_info *mode)
10392de6bb97SJacopo Mondi {
10402de6bb97SJacopo Mondi 	if (ov5640_is_csi2(sensor))
10412de6bb97SJacopo Mondi 		return &mode->csi2_timings;
10422de6bb97SJacopo Mondi 
10432de6bb97SJacopo Mondi 	return &mode->dvp_timings;
10442de6bb97SJacopo Mondi }
10452de6bb97SJacopo Mondi 
104619a81c14SSteve Longerbeam static int ov5640_init_slave_id(struct ov5640_dev *sensor)
104719a81c14SSteve Longerbeam {
104819a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
104919a81c14SSteve Longerbeam 	struct i2c_msg msg;
105019a81c14SSteve Longerbeam 	u8 buf[3];
105119a81c14SSteve Longerbeam 	int ret;
105219a81c14SSteve Longerbeam 
105319a81c14SSteve Longerbeam 	if (client->addr == OV5640_DEFAULT_SLAVE_ID)
105419a81c14SSteve Longerbeam 		return 0;
105519a81c14SSteve Longerbeam 
105619a81c14SSteve Longerbeam 	buf[0] = OV5640_REG_SLAVE_ID >> 8;
105719a81c14SSteve Longerbeam 	buf[1] = OV5640_REG_SLAVE_ID & 0xff;
105819a81c14SSteve Longerbeam 	buf[2] = client->addr << 1;
105919a81c14SSteve Longerbeam 
106019a81c14SSteve Longerbeam 	msg.addr = OV5640_DEFAULT_SLAVE_ID;
106119a81c14SSteve Longerbeam 	msg.flags = 0;
106219a81c14SSteve Longerbeam 	msg.buf = buf;
106319a81c14SSteve Longerbeam 	msg.len = sizeof(buf);
106419a81c14SSteve Longerbeam 
106519a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, &msg, 1);
106619a81c14SSteve Longerbeam 	if (ret < 0) {
106719a81c14SSteve Longerbeam 		dev_err(&client->dev, "%s: failed with %d\n", __func__, ret);
106819a81c14SSteve Longerbeam 		return ret;
106919a81c14SSteve Longerbeam 	}
107019a81c14SSteve Longerbeam 
107119a81c14SSteve Longerbeam 	return 0;
107219a81c14SSteve Longerbeam }
107319a81c14SSteve Longerbeam 
107419a81c14SSteve Longerbeam static int ov5640_write_reg(struct ov5640_dev *sensor, u16 reg, u8 val)
107519a81c14SSteve Longerbeam {
107619a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
107719a81c14SSteve Longerbeam 	struct i2c_msg msg;
107819a81c14SSteve Longerbeam 	u8 buf[3];
107919a81c14SSteve Longerbeam 	int ret;
108019a81c14SSteve Longerbeam 
108119a81c14SSteve Longerbeam 	buf[0] = reg >> 8;
108219a81c14SSteve Longerbeam 	buf[1] = reg & 0xff;
108319a81c14SSteve Longerbeam 	buf[2] = val;
108419a81c14SSteve Longerbeam 
108519a81c14SSteve Longerbeam 	msg.addr = client->addr;
108619a81c14SSteve Longerbeam 	msg.flags = client->flags;
108719a81c14SSteve Longerbeam 	msg.buf = buf;
108819a81c14SSteve Longerbeam 	msg.len = sizeof(buf);
108919a81c14SSteve Longerbeam 
109019a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, &msg, 1);
109119a81c14SSteve Longerbeam 	if (ret < 0) {
10923924c623SHugues Fruchet 		dev_err(&client->dev, "%s: error: reg=%x, val=%x\n",
109319a81c14SSteve Longerbeam 			__func__, reg, val);
109419a81c14SSteve Longerbeam 		return ret;
109519a81c14SSteve Longerbeam 	}
109619a81c14SSteve Longerbeam 
109719a81c14SSteve Longerbeam 	return 0;
109819a81c14SSteve Longerbeam }
109919a81c14SSteve Longerbeam 
110019a81c14SSteve Longerbeam static int ov5640_read_reg(struct ov5640_dev *sensor, u16 reg, u8 *val)
110119a81c14SSteve Longerbeam {
110219a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
110319a81c14SSteve Longerbeam 	struct i2c_msg msg[2];
110419a81c14SSteve Longerbeam 	u8 buf[2];
110519a81c14SSteve Longerbeam 	int ret;
110619a81c14SSteve Longerbeam 
110719a81c14SSteve Longerbeam 	buf[0] = reg >> 8;
110819a81c14SSteve Longerbeam 	buf[1] = reg & 0xff;
110919a81c14SSteve Longerbeam 
111019a81c14SSteve Longerbeam 	msg[0].addr = client->addr;
111119a81c14SSteve Longerbeam 	msg[0].flags = client->flags;
111219a81c14SSteve Longerbeam 	msg[0].buf = buf;
111319a81c14SSteve Longerbeam 	msg[0].len = sizeof(buf);
111419a81c14SSteve Longerbeam 
111519a81c14SSteve Longerbeam 	msg[1].addr = client->addr;
111619a81c14SSteve Longerbeam 	msg[1].flags = client->flags | I2C_M_RD;
111719a81c14SSteve Longerbeam 	msg[1].buf = buf;
111819a81c14SSteve Longerbeam 	msg[1].len = 1;
111919a81c14SSteve Longerbeam 
112019a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, msg, 2);
11213924c623SHugues Fruchet 	if (ret < 0) {
11223924c623SHugues Fruchet 		dev_err(&client->dev, "%s: error: reg=%x\n",
11233924c623SHugues Fruchet 			__func__, reg);
112419a81c14SSteve Longerbeam 		return ret;
11253924c623SHugues Fruchet 	}
112619a81c14SSteve Longerbeam 
112719a81c14SSteve Longerbeam 	*val = buf[0];
112819a81c14SSteve Longerbeam 	return 0;
112919a81c14SSteve Longerbeam }
113019a81c14SSteve Longerbeam 
113119a81c14SSteve Longerbeam static int ov5640_read_reg16(struct ov5640_dev *sensor, u16 reg, u16 *val)
113219a81c14SSteve Longerbeam {
113319a81c14SSteve Longerbeam 	u8 hi, lo;
113419a81c14SSteve Longerbeam 	int ret;
113519a81c14SSteve Longerbeam 
113619a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg, &hi);
113719a81c14SSteve Longerbeam 	if (ret)
113819a81c14SSteve Longerbeam 		return ret;
113919a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg + 1, &lo);
114019a81c14SSteve Longerbeam 	if (ret)
114119a81c14SSteve Longerbeam 		return ret;
114219a81c14SSteve Longerbeam 
114319a81c14SSteve Longerbeam 	*val = ((u16)hi << 8) | (u16)lo;
114419a81c14SSteve Longerbeam 	return 0;
114519a81c14SSteve Longerbeam }
114619a81c14SSteve Longerbeam 
114719a81c14SSteve Longerbeam static int ov5640_write_reg16(struct ov5640_dev *sensor, u16 reg, u16 val)
114819a81c14SSteve Longerbeam {
114919a81c14SSteve Longerbeam 	int ret;
115019a81c14SSteve Longerbeam 
115119a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, reg, val >> 8);
115219a81c14SSteve Longerbeam 	if (ret)
115319a81c14SSteve Longerbeam 		return ret;
115419a81c14SSteve Longerbeam 
115519a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, reg + 1, val & 0xff);
115619a81c14SSteve Longerbeam }
115719a81c14SSteve Longerbeam 
115819a81c14SSteve Longerbeam static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg,
115919a81c14SSteve Longerbeam 			  u8 mask, u8 val)
116019a81c14SSteve Longerbeam {
116119a81c14SSteve Longerbeam 	u8 readval;
116219a81c14SSteve Longerbeam 	int ret;
116319a81c14SSteve Longerbeam 
116419a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg, &readval);
116519a81c14SSteve Longerbeam 	if (ret)
116619a81c14SSteve Longerbeam 		return ret;
116719a81c14SSteve Longerbeam 
116819a81c14SSteve Longerbeam 	readval &= ~mask;
116919a81c14SSteve Longerbeam 	val &= mask;
117019a81c14SSteve Longerbeam 	val |= readval;
117119a81c14SSteve Longerbeam 
117219a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, reg, val);
117319a81c14SSteve Longerbeam }
117419a81c14SSteve Longerbeam 
1175aa288248SMaxime Ripard /*
1176aa288248SMaxime Ripard  * After trying the various combinations, reading various
1177f8a7647dSMauro Carvalho Chehab  * documentations spread around the net, and from the various
1178aa288248SMaxime Ripard  * feedback, the clock tree is probably as follows:
1179aa288248SMaxime Ripard  *
1180aa288248SMaxime Ripard  *   +--------------+
1181aa288248SMaxime Ripard  *   |  Ext. Clock  |
1182aa288248SMaxime Ripard  *   +-+------------+
1183aa288248SMaxime Ripard  *     |  +----------+
1184aa288248SMaxime Ripard  *     +->|   PLL1   | - reg 0x3036, for the multiplier
1185aa288248SMaxime Ripard  *        +-+--------+ - reg 0x3037, bits 0-3 for the pre-divider
1186aa288248SMaxime Ripard  *          |  +--------------+
1187aa288248SMaxime Ripard  *          +->| System Clock |  - reg 0x3035, bits 4-7
1188aa288248SMaxime Ripard  *             +-+------------+
1189aa288248SMaxime Ripard  *               |  +--------------+
1190aa288248SMaxime Ripard  *               +->| MIPI Divider | - reg 0x3035, bits 0-3
1191aa288248SMaxime Ripard  *               |  +-+------------+
1192aa288248SMaxime Ripard  *               |    +----------------> MIPI SCLK
1193aa288248SMaxime Ripard  *               |    +  +-----+
1194aa288248SMaxime Ripard  *               |    +->| / 2 |-------> MIPI BIT CLK
1195aa288248SMaxime Ripard  *               |       +-----+
1196aa288248SMaxime Ripard  *               |  +--------------+
1197aa288248SMaxime Ripard  *               +->| PLL Root Div | - reg 0x3037, bit 4
1198aa288248SMaxime Ripard  *                  +-+------------+
1199aa288248SMaxime Ripard  *                    |  +---------+
12004c85f628SPaul Kocialkowski  *                    +->| Bit Div | - reg 0x3034, bits 0-3
1201aa288248SMaxime Ripard  *                       +-+-------+
1202aa288248SMaxime Ripard  *                         |  +-------------+
1203aa288248SMaxime Ripard  *                         +->| SCLK Div    | - reg 0x3108, bits 0-1
1204aa288248SMaxime Ripard  *                         |  +-+-----------+
1205aa288248SMaxime Ripard  *                         |    +---------------> SCLK
1206aa288248SMaxime Ripard  *                         |  +-------------+
1207aa288248SMaxime Ripard  *                         +->| SCLK 2X Div | - reg 0x3108, bits 2-3
1208aa288248SMaxime Ripard  *                         |  +-+-----------+
1209aa288248SMaxime Ripard  *                         |    +---------------> SCLK 2X
1210aa288248SMaxime Ripard  *                         |  +-------------+
1211aa288248SMaxime Ripard  *                         +->| PCLK Div    | - reg 0x3108, bits 4-5
1212aa288248SMaxime Ripard  *                            ++------------+
1213aa288248SMaxime Ripard  *                             +  +-----------+
1214aa288248SMaxime Ripard  *                             +->|   P_DIV   | - reg 0x3035, bits 0-3
1215aa288248SMaxime Ripard  *                                +-----+-----+
1216aa288248SMaxime Ripard  *                                       +------------> PCLK
1217aa288248SMaxime Ripard  *
12186c957ed7SJacopo Mondi  * There seems to be also constraints:
1219aa288248SMaxime Ripard  *  - the PLL pre-divider output rate should be in the 4-27MHz range
1220aa288248SMaxime Ripard  *  - the PLL multiplier output rate should be in the 500-1000MHz range
1221aa288248SMaxime Ripard  *  - PCLK >= SCLK * 2 in YUV, >= SCLK in Raw or JPEG
1222aa288248SMaxime Ripard  */
1223aa288248SMaxime Ripard 
1224aa288248SMaxime Ripard /*
1225aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1226aa288248SMaxime Ripard  * set to 3 in the vendor kernels.
1227aa288248SMaxime Ripard  */
1228aa288248SMaxime Ripard #define OV5640_PLL_PREDIV	3
1229aa288248SMaxime Ripard 
1230aa288248SMaxime Ripard #define OV5640_PLL_MULT_MIN	4
1231aa288248SMaxime Ripard #define OV5640_PLL_MULT_MAX	252
1232aa288248SMaxime Ripard 
1233aa288248SMaxime Ripard /*
1234aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 16, but the value is
1235aa288248SMaxime Ripard  * always set to either 1 or 2 in the vendor kernels.
1236aa288248SMaxime Ripard  */
1237aa288248SMaxime Ripard #define OV5640_SYSDIV_MIN	1
1238aa288248SMaxime Ripard #define OV5640_SYSDIV_MAX	16
1239aa288248SMaxime Ripard 
1240aa288248SMaxime Ripard /*
1241aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 2, but the value is always
1242aa288248SMaxime Ripard  * set to 2 in the vendor kernels.
1243aa288248SMaxime Ripard  */
1244aa288248SMaxime Ripard #define OV5640_PLL_ROOT_DIV			2
1245aa288248SMaxime Ripard #define OV5640_PLL_CTRL3_PLL_ROOT_DIV_2		BIT(4)
1246aa288248SMaxime Ripard 
1247aa288248SMaxime Ripard /*
1248aa288248SMaxime Ripard  * We only supports 8-bit formats at the moment
1249aa288248SMaxime Ripard  */
1250aa288248SMaxime Ripard #define OV5640_BIT_DIV				2
1251aa288248SMaxime Ripard #define OV5640_PLL_CTRL0_MIPI_MODE_8BIT		0x08
1252aa288248SMaxime Ripard 
1253aa288248SMaxime Ripard /*
1254aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1255aa288248SMaxime Ripard  * set to 2 in the vendor kernels.
1256aa288248SMaxime Ripard  */
1257aa288248SMaxime Ripard #define OV5640_SCLK_ROOT_DIV	2
1258aa288248SMaxime Ripard 
1259aa288248SMaxime Ripard /*
1260aa288248SMaxime Ripard  * This is hardcoded so that the consistency is maintained between SCLK and
1261aa288248SMaxime Ripard  * SCLK 2x.
1262aa288248SMaxime Ripard  */
1263aa288248SMaxime Ripard #define OV5640_SCLK2X_ROOT_DIV (OV5640_SCLK_ROOT_DIV / 2)
1264aa288248SMaxime Ripard 
1265aa288248SMaxime Ripard /*
1266aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1267aa288248SMaxime Ripard  * set to 1 in the vendor kernels.
1268aa288248SMaxime Ripard  */
1269aa288248SMaxime Ripard #define OV5640_PCLK_ROOT_DIV			1
1270aa288248SMaxime Ripard #define OV5640_PLL_SYS_ROOT_DIVIDER_BYPASS	0x00
1271aa288248SMaxime Ripard 
1272aa288248SMaxime Ripard static unsigned long ov5640_compute_sys_clk(struct ov5640_dev *sensor,
1273aa288248SMaxime Ripard 					    u8 pll_prediv, u8 pll_mult,
1274aa288248SMaxime Ripard 					    u8 sysdiv)
1275aa288248SMaxime Ripard {
1276aa288248SMaxime Ripard 	unsigned long sysclk = sensor->xclk_freq / pll_prediv * pll_mult;
1277aa288248SMaxime Ripard 
1278aa288248SMaxime Ripard 	/* PLL1 output cannot exceed 1GHz. */
1279aa288248SMaxime Ripard 	if (sysclk / 1000000 > 1000)
1280aa288248SMaxime Ripard 		return 0;
1281aa288248SMaxime Ripard 
1282aa288248SMaxime Ripard 	return sysclk / sysdiv;
1283aa288248SMaxime Ripard }
1284aa288248SMaxime Ripard 
1285aa288248SMaxime Ripard static unsigned long ov5640_calc_sys_clk(struct ov5640_dev *sensor,
1286aa288248SMaxime Ripard 					 unsigned long rate,
1287aa288248SMaxime Ripard 					 u8 *pll_prediv, u8 *pll_mult,
1288aa288248SMaxime Ripard 					 u8 *sysdiv)
1289aa288248SMaxime Ripard {
1290aa288248SMaxime Ripard 	unsigned long best = ~0;
1291aa288248SMaxime Ripard 	u8 best_sysdiv = 1, best_mult = 1;
1292aa288248SMaxime Ripard 	u8 _sysdiv, _pll_mult;
1293aa288248SMaxime Ripard 
1294aa288248SMaxime Ripard 	for (_sysdiv = OV5640_SYSDIV_MIN;
1295aa288248SMaxime Ripard 	     _sysdiv <= OV5640_SYSDIV_MAX;
1296aa288248SMaxime Ripard 	     _sysdiv++) {
1297aa288248SMaxime Ripard 		for (_pll_mult = OV5640_PLL_MULT_MIN;
1298aa288248SMaxime Ripard 		     _pll_mult <= OV5640_PLL_MULT_MAX;
1299aa288248SMaxime Ripard 		     _pll_mult++) {
1300aa288248SMaxime Ripard 			unsigned long _rate;
1301aa288248SMaxime Ripard 
1302aa288248SMaxime Ripard 			/*
1303aa288248SMaxime Ripard 			 * The PLL multiplier cannot be odd if above
1304aa288248SMaxime Ripard 			 * 127.
1305aa288248SMaxime Ripard 			 */
1306aa288248SMaxime Ripard 			if (_pll_mult > 127 && (_pll_mult % 2))
1307aa288248SMaxime Ripard 				continue;
1308aa288248SMaxime Ripard 
1309aa288248SMaxime Ripard 			_rate = ov5640_compute_sys_clk(sensor,
1310aa288248SMaxime Ripard 						       OV5640_PLL_PREDIV,
1311aa288248SMaxime Ripard 						       _pll_mult, _sysdiv);
1312aa288248SMaxime Ripard 
1313aa288248SMaxime Ripard 			/*
1314aa288248SMaxime Ripard 			 * We have reached the maximum allowed PLL1 output,
1315aa288248SMaxime Ripard 			 * increase sysdiv.
1316aa288248SMaxime Ripard 			 */
13172e3df204SAdam Ford 			if (!_rate)
1318aa288248SMaxime Ripard 				break;
1319aa288248SMaxime Ripard 
1320aa288248SMaxime Ripard 			/*
1321aa288248SMaxime Ripard 			 * Prefer rates above the expected clock rate than
1322aa288248SMaxime Ripard 			 * below, even if that means being less precise.
1323aa288248SMaxime Ripard 			 */
1324aa288248SMaxime Ripard 			if (_rate < rate)
1325aa288248SMaxime Ripard 				continue;
1326aa288248SMaxime Ripard 
1327aa288248SMaxime Ripard 			if (abs(rate - _rate) < abs(rate - best)) {
1328aa288248SMaxime Ripard 				best = _rate;
1329aa288248SMaxime Ripard 				best_sysdiv = _sysdiv;
1330aa288248SMaxime Ripard 				best_mult = _pll_mult;
1331aa288248SMaxime Ripard 			}
1332aa288248SMaxime Ripard 
1333aa288248SMaxime Ripard 			if (_rate == rate)
1334aa288248SMaxime Ripard 				goto out;
1335aa288248SMaxime Ripard 		}
1336aa288248SMaxime Ripard 	}
1337aa288248SMaxime Ripard 
1338aa288248SMaxime Ripard out:
1339aa288248SMaxime Ripard 	*sysdiv = best_sysdiv;
1340aa288248SMaxime Ripard 	*pll_prediv = OV5640_PLL_PREDIV;
1341aa288248SMaxime Ripard 	*pll_mult = best_mult;
1342aa288248SMaxime Ripard 
1343aa288248SMaxime Ripard 	return best;
1344aa288248SMaxime Ripard }
1345aa288248SMaxime Ripard 
1346aa288248SMaxime Ripard /*
1347aa288248SMaxime Ripard  * ov5640_set_mipi_pclk() - Calculate the clock tree configuration values
1348aa288248SMaxime Ripard  *			    for the MIPI CSI-2 output.
1349aa288248SMaxime Ripard  */
13506c957ed7SJacopo Mondi static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor)
1351aa288248SMaxime Ripard {
13526c957ed7SJacopo Mondi 	u8 bit_div, mipi_div, pclk_div, sclk_div, sclk2x_div, root_div;
1353aa288248SMaxime Ripard 	u8 prediv, mult, sysdiv;
13546c957ed7SJacopo Mondi 	unsigned long link_freq;
13556c957ed7SJacopo Mondi 	unsigned long sysclk;
13566c957ed7SJacopo Mondi 	u8 pclk_period;
13576c957ed7SJacopo Mondi 	u32 sample_rate;
13586c957ed7SJacopo Mondi 	u32 num_lanes;
1359aa288248SMaxime Ripard 	int ret;
1360aa288248SMaxime Ripard 
13616c957ed7SJacopo Mondi 	/* Use the link freq computed at ov5640_update_pixel_rate() time. */
13626c957ed7SJacopo Mondi 	link_freq = sensor->current_link_freq;
13636c957ed7SJacopo Mondi 
1364aa288248SMaxime Ripard 	/*
13656c957ed7SJacopo Mondi 	 * - mipi_div - Additional divider for the MIPI lane clock.
13666c957ed7SJacopo Mondi 	 *
13676c957ed7SJacopo Mondi 	 * Higher link frequencies would make sysclk > 1GHz.
13686c957ed7SJacopo Mondi 	 * Keep the sysclk low and do not divide in the MIPI domain.
1369aa288248SMaxime Ripard 	 */
13706c957ed7SJacopo Mondi 	if (link_freq > OV5640_LINK_RATE_MAX)
13716c957ed7SJacopo Mondi 		mipi_div = 1;
1372aa288248SMaxime Ripard 	else
13736c957ed7SJacopo Mondi 		mipi_div = 2;
1374aa288248SMaxime Ripard 
13756c957ed7SJacopo Mondi 	sysclk = link_freq * mipi_div;
13766c957ed7SJacopo Mondi 	ov5640_calc_sys_clk(sensor, sysclk, &prediv, &mult, &sysdiv);
1377aa288248SMaxime Ripard 
13786c957ed7SJacopo Mondi 	/*
13796c957ed7SJacopo Mondi 	 * Adjust PLL parameters to maintain the MIPI_SCLK-to-PCLK ratio.
13806c957ed7SJacopo Mondi 	 *
13816c957ed7SJacopo Mondi 	 * - root_div = 2 (fixed)
13826c957ed7SJacopo Mondi 	 * - bit_div : MIPI 8-bit = 2; MIPI 10-bit = 2.5
13836c957ed7SJacopo Mondi 	 * - pclk_div = 1 (fixed)
13846c957ed7SJacopo Mondi 	 * - p_div  = (2 lanes ? mipi_div : 2 * mipi_div)
13856c957ed7SJacopo Mondi 	 *
13866c957ed7SJacopo Mondi 	 * This results in the following MIPI_SCLK depending on the number
13876c957ed7SJacopo Mondi 	 * of lanes:
13886c957ed7SJacopo Mondi 	 *
13896c957ed7SJacopo Mondi 	 * - 2 lanes: MIPI_SCLK = (4 or 5) * PCLK
13906c957ed7SJacopo Mondi 	 * - 1 lanes: MIPI_SCLK = (8 or 10) * PCLK
13916c957ed7SJacopo Mondi 	 */
13926c957ed7SJacopo Mondi 	root_div = OV5640_PLL_CTRL3_PLL_ROOT_DIV_2;
13936c957ed7SJacopo Mondi 	bit_div =  OV5640_PLL_CTRL0_MIPI_MODE_8BIT;
13946c957ed7SJacopo Mondi 	pclk_div = ilog2(OV5640_PCLK_ROOT_DIV);
1395aa288248SMaxime Ripard 
13966c957ed7SJacopo Mondi 	/*
13976c957ed7SJacopo Mondi 	 * Scaler clock:
13986c957ed7SJacopo Mondi 	 * - YUV: PCLK >= 2 * SCLK
13996c957ed7SJacopo Mondi 	 * - RAW or JPEG: PCLK >= SCLK
14006c957ed7SJacopo Mondi 	 * - sclk2x_div = sclk_div / 2
14016c957ed7SJacopo Mondi 	 */
14026c957ed7SJacopo Mondi 	sclk_div = ilog2(OV5640_SCLK_ROOT_DIV);
14036c957ed7SJacopo Mondi 	sclk2x_div = ilog2(OV5640_SCLK2X_ROOT_DIV);
14046c957ed7SJacopo Mondi 
14056c957ed7SJacopo Mondi 	/*
14066c957ed7SJacopo Mondi 	 * Set the pixel clock period expressed in ns with 1-bit decimal
14076c957ed7SJacopo Mondi 	 * (0x01=0.5ns).
14086c957ed7SJacopo Mondi 	 *
14096c957ed7SJacopo Mondi 	 * The register is very briefly documented. In the OV5645 datasheet it
14106c957ed7SJacopo Mondi 	 * is described as (2 * pclk period), and from testing it seems the
14116c957ed7SJacopo Mondi 	 * actual definition is 2 * 8-bit sample period.
14126c957ed7SJacopo Mondi 	 *
14136c957ed7SJacopo Mondi 	 * 2 * sample_period = (mipi_clk * 2 * num_lanes / bpp) * (bpp / 8) / 2
14146c957ed7SJacopo Mondi 	 */
14156c957ed7SJacopo Mondi 	num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes;
14166c957ed7SJacopo Mondi 	sample_rate = (link_freq * mipi_div * num_lanes * 2) / 16;
14176c957ed7SJacopo Mondi 	pclk_period = 2000000000UL / sample_rate;
14186c957ed7SJacopo Mondi 
14196c957ed7SJacopo Mondi 	/* Program the clock tree registers. */
14206c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0, 0x0f, bit_div);
14216c957ed7SJacopo Mondi 	if (ret)
14226c957ed7SJacopo Mondi 		return ret;
14236c957ed7SJacopo Mondi 
14246c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, 0xff,
14256c957ed7SJacopo Mondi 			     (sysdiv << 4) | mipi_div);
1426aa288248SMaxime Ripard 	if (ret)
1427aa288248SMaxime Ripard 		return ret;
1428aa288248SMaxime Ripard 
1429aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2, 0xff, mult);
1430aa288248SMaxime Ripard 	if (ret)
1431aa288248SMaxime Ripard 		return ret;
1432aa288248SMaxime Ripard 
14336c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3, 0x1f,
14346c957ed7SJacopo Mondi 			     root_div | prediv);
1435aa288248SMaxime Ripard 	if (ret)
1436aa288248SMaxime Ripard 		return ret;
1437aa288248SMaxime Ripard 
14386c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
14396c957ed7SJacopo Mondi 			     (pclk_div << 4) | (sclk2x_div << 2) | sclk_div);
14406c957ed7SJacopo Mondi 	if (ret)
14416c957ed7SJacopo Mondi 		return ret;
14426c957ed7SJacopo Mondi 
14436c957ed7SJacopo Mondi 	return ov5640_write_reg(sensor, OV5640_REG_PCLK_PERIOD, pclk_period);
14446c957ed7SJacopo Mondi }
14456c957ed7SJacopo Mondi 
14466c957ed7SJacopo Mondi static u32 ov5640_calc_pixel_rate(struct ov5640_dev *sensor)
14476c957ed7SJacopo Mondi {
14483145efcdSJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
14495113d5b3SJacopo Mondi 	const struct ov5640_timings *timings = &mode->dvp_timings;
14506c957ed7SJacopo Mondi 	u32 rate;
14516c957ed7SJacopo Mondi 
14525113d5b3SJacopo Mondi 	rate = timings->htot * (timings->crop.height + timings->vblank_def);
14536c957ed7SJacopo Mondi 	rate *= ov5640_framerates[sensor->current_fr];
14546c957ed7SJacopo Mondi 
14556c957ed7SJacopo Mondi 	return rate;
1456aa288248SMaxime Ripard }
1457aa288248SMaxime Ripard 
1458aa288248SMaxime Ripard static unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor,
1459aa288248SMaxime Ripard 				      unsigned long rate,
1460aa288248SMaxime Ripard 				      u8 *pll_prediv, u8 *pll_mult, u8 *sysdiv,
1461aa288248SMaxime Ripard 				      u8 *pll_rdiv, u8 *bit_div, u8 *pclk_div)
1462aa288248SMaxime Ripard {
1463aa288248SMaxime Ripard 	unsigned long _rate = rate * OV5640_PLL_ROOT_DIV * OV5640_BIT_DIV *
1464aa288248SMaxime Ripard 				OV5640_PCLK_ROOT_DIV;
1465aa288248SMaxime Ripard 
1466aa288248SMaxime Ripard 	_rate = ov5640_calc_sys_clk(sensor, _rate, pll_prediv, pll_mult,
1467aa288248SMaxime Ripard 				    sysdiv);
1468aa288248SMaxime Ripard 	*pll_rdiv = OV5640_PLL_ROOT_DIV;
1469aa288248SMaxime Ripard 	*bit_div = OV5640_BIT_DIV;
1470aa288248SMaxime Ripard 	*pclk_div = OV5640_PCLK_ROOT_DIV;
1471aa288248SMaxime Ripard 
1472aa288248SMaxime Ripard 	return _rate / *pll_rdiv / *bit_div / *pclk_div;
1473aa288248SMaxime Ripard }
1474aa288248SMaxime Ripard 
14756c957ed7SJacopo Mondi static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor)
1476aa288248SMaxime Ripard {
1477aa288248SMaxime Ripard 	u8 prediv, mult, sysdiv, pll_rdiv, bit_div, pclk_div;
14786c957ed7SJacopo Mondi 	u32 rate;
1479aa288248SMaxime Ripard 	int ret;
1480aa288248SMaxime Ripard 
14816c957ed7SJacopo Mondi 	rate = ov5640_calc_pixel_rate(sensor);
14826c957ed7SJacopo Mondi 	rate *= ov5640_code_to_bpp(sensor->fmt.code);
14836c957ed7SJacopo Mondi 	rate /= sensor->ep.bus.parallel.bus_width;
14846c957ed7SJacopo Mondi 
1485aa288248SMaxime Ripard 	ov5640_calc_pclk(sensor, rate, &prediv, &mult, &sysdiv, &pll_rdiv,
1486aa288248SMaxime Ripard 			 &bit_div, &pclk_div);
1487aa288248SMaxime Ripard 
1488aa288248SMaxime Ripard 	if (bit_div == 2)
1489aa288248SMaxime Ripard 		bit_div = 8;
1490aa288248SMaxime Ripard 
1491aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0,
1492aa288248SMaxime Ripard 			     0x0f, bit_div);
1493aa288248SMaxime Ripard 	if (ret)
1494aa288248SMaxime Ripard 		return ret;
1495aa288248SMaxime Ripard 
1496aa288248SMaxime Ripard 	/*
1497aa288248SMaxime Ripard 	 * We need to set sysdiv according to the clock, and to clear
1498aa288248SMaxime Ripard 	 * the MIPI divider.
1499aa288248SMaxime Ripard 	 */
1500aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1,
1501aa288248SMaxime Ripard 			     0xff, sysdiv << 4);
1502aa288248SMaxime Ripard 	if (ret)
1503aa288248SMaxime Ripard 		return ret;
1504aa288248SMaxime Ripard 
1505aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2,
1506aa288248SMaxime Ripard 			     0xff, mult);
1507aa288248SMaxime Ripard 	if (ret)
1508aa288248SMaxime Ripard 		return ret;
1509aa288248SMaxime Ripard 
1510aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3,
1511aa288248SMaxime Ripard 			     0x1f, prediv | ((pll_rdiv - 1) << 4));
1512aa288248SMaxime Ripard 	if (ret)
1513aa288248SMaxime Ripard 		return ret;
1514aa288248SMaxime Ripard 
1515aa288248SMaxime Ripard 	return ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x30,
1516aa288248SMaxime Ripard 			      (ilog2(pclk_div) << 4));
1517aa288248SMaxime Ripard }
1518aa288248SMaxime Ripard 
15197cb013b1SChen-Yu Tsai /* set JPEG framing sizes */
15207cb013b1SChen-Yu Tsai static int ov5640_set_jpeg_timings(struct ov5640_dev *sensor,
15217cb013b1SChen-Yu Tsai 				   const struct ov5640_mode_info *mode)
15227cb013b1SChen-Yu Tsai {
15237cb013b1SChen-Yu Tsai 	int ret;
15247cb013b1SChen-Yu Tsai 
15252b5c18f9SChen-Yu Tsai 	/*
15262b5c18f9SChen-Yu Tsai 	 * compression mode 3 timing
15272b5c18f9SChen-Yu Tsai 	 *
15282b5c18f9SChen-Yu Tsai 	 * Data is transmitted with programmable width (VFIFO_HSIZE).
15292b5c18f9SChen-Yu Tsai 	 * No padding done. Last line may have less data. Varying
15302b5c18f9SChen-Yu Tsai 	 * number of lines per frame, depending on amount of data.
15312b5c18f9SChen-Yu Tsai 	 */
15322b5c18f9SChen-Yu Tsai 	ret = ov5640_mod_reg(sensor, OV5640_REG_JPG_MODE_SELECT, 0x7, 0x3);
15332b5c18f9SChen-Yu Tsai 	if (ret < 0)
15342b5c18f9SChen-Yu Tsai 		return ret;
15352b5c18f9SChen-Yu Tsai 
15365113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_VFIFO_HSIZE, mode->width);
15377cb013b1SChen-Yu Tsai 	if (ret < 0)
15387cb013b1SChen-Yu Tsai 		return ret;
15397cb013b1SChen-Yu Tsai 
15405113d5b3SJacopo Mondi 	return ov5640_write_reg16(sensor, OV5640_REG_VFIFO_VSIZE, mode->height);
15417cb013b1SChen-Yu Tsai }
15427cb013b1SChen-Yu Tsai 
154319a81c14SSteve Longerbeam /* download ov5640 settings to sensor through i2c */
1544bad1774eSJacopo Mondi static int ov5640_set_timings(struct ov5640_dev *sensor,
1545bad1774eSJacopo Mondi 			      const struct ov5640_mode_info *mode)
1546bad1774eSJacopo Mondi {
15475113d5b3SJacopo Mondi 	const struct ov5640_timings *timings;
15485113d5b3SJacopo Mondi 	const struct v4l2_rect *analog_crop;
15495113d5b3SJacopo Mondi 	const struct v4l2_rect *crop;
1550bad1774eSJacopo Mondi 	int ret;
1551bad1774eSJacopo Mondi 
15527cb013b1SChen-Yu Tsai 	if (sensor->fmt.code == MEDIA_BUS_FMT_JPEG_1X8) {
15537cb013b1SChen-Yu Tsai 		ret = ov5640_set_jpeg_timings(sensor, mode);
15547cb013b1SChen-Yu Tsai 		if (ret < 0)
15557cb013b1SChen-Yu Tsai 			return ret;
15567cb013b1SChen-Yu Tsai 	}
15577cb013b1SChen-Yu Tsai 
15582de6bb97SJacopo Mondi 	timings = ov5640_timings(sensor, mode);
15595113d5b3SJacopo Mondi 	analog_crop = &timings->analog_crop;
15605113d5b3SJacopo Mondi 	crop = &timings->crop;
15615113d5b3SJacopo Mondi 
15623145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HS,
15633145efcdSJacopo Mondi 				 analog_crop->left);
1564bad1774eSJacopo Mondi 	if (ret < 0)
1565bad1774eSJacopo Mondi 		return ret;
1566bad1774eSJacopo Mondi 
15673145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VS,
15683145efcdSJacopo Mondi 				 analog_crop->top);
15693145efcdSJacopo Mondi 	if (ret < 0)
15703145efcdSJacopo Mondi 		return ret;
15713145efcdSJacopo Mondi 
15723145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HW,
15733145efcdSJacopo Mondi 				 analog_crop->left + analog_crop->width - 1);
15743145efcdSJacopo Mondi 	if (ret < 0)
15753145efcdSJacopo Mondi 		return ret;
15763145efcdSJacopo Mondi 
15773145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VH,
15783145efcdSJacopo Mondi 				 analog_crop->top + analog_crop->height - 1);
15793145efcdSJacopo Mondi 	if (ret < 0)
15803145efcdSJacopo Mondi 		return ret;
15813145efcdSJacopo Mondi 
15823145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HOFFS, crop->left);
15833145efcdSJacopo Mondi 	if (ret < 0)
15843145efcdSJacopo Mondi 		return ret;
15853145efcdSJacopo Mondi 
15863145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VOFFS, crop->top);
15873145efcdSJacopo Mondi 	if (ret < 0)
15883145efcdSJacopo Mondi 		return ret;
15893145efcdSJacopo Mondi 
15905113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->width);
15913145efcdSJacopo Mondi 	if (ret < 0)
15923145efcdSJacopo Mondi 		return ret;
15933145efcdSJacopo Mondi 
15945113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, mode->height);
1595bad1774eSJacopo Mondi 	if (ret < 0)
1596bad1774eSJacopo Mondi 		return ret;
1597bad1774eSJacopo Mondi 
15985113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, timings->htot);
1599bad1774eSJacopo Mondi 	if (ret < 0)
1600bad1774eSJacopo Mondi 		return ret;
1601bad1774eSJacopo Mondi 
16023145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS,
16035113d5b3SJacopo Mondi 				 mode->height + timings->vblank_def);
16043145efcdSJacopo Mondi 	if (ret < 0)
16053145efcdSJacopo Mondi 		return ret;
16063145efcdSJacopo Mondi 
16073145efcdSJacopo Mondi 	return 0;
1608bad1774eSJacopo Mondi }
1609bad1774eSJacopo Mondi 
161019a81c14SSteve Longerbeam static int ov5640_load_regs(struct ov5640_dev *sensor,
161119a81c14SSteve Longerbeam 			    const struct ov5640_mode_info *mode)
161219a81c14SSteve Longerbeam {
161319a81c14SSteve Longerbeam 	const struct reg_value *regs = mode->reg_data;
161419a81c14SSteve Longerbeam 	unsigned int i;
161519a81c14SSteve Longerbeam 	u32 delay_ms;
161619a81c14SSteve Longerbeam 	u16 reg_addr;
161719a81c14SSteve Longerbeam 	u8 mask, val;
161819a81c14SSteve Longerbeam 	int ret = 0;
161919a81c14SSteve Longerbeam 
162019a81c14SSteve Longerbeam 	for (i = 0; i < mode->reg_data_size; ++i, ++regs) {
162119a81c14SSteve Longerbeam 		delay_ms = regs->delay_ms;
162219a81c14SSteve Longerbeam 		reg_addr = regs->reg_addr;
162319a81c14SSteve Longerbeam 		val = regs->val;
162419a81c14SSteve Longerbeam 		mask = regs->mask;
162519a81c14SSteve Longerbeam 
16263b987d70SLad Prabhakar 		/* remain in power down mode for DVP */
16273b987d70SLad Prabhakar 		if (regs->reg_addr == OV5640_REG_SYS_CTRL0 &&
16283b987d70SLad Prabhakar 		    val == OV5640_REG_SYS_CTRL0_SW_PWUP &&
16298e823f5cSJacopo Mondi 		    !ov5640_is_csi2(sensor))
16303b987d70SLad Prabhakar 			continue;
16313b987d70SLad Prabhakar 
163219a81c14SSteve Longerbeam 		if (mask)
163319a81c14SSteve Longerbeam 			ret = ov5640_mod_reg(sensor, reg_addr, mask, val);
163419a81c14SSteve Longerbeam 		else
163519a81c14SSteve Longerbeam 			ret = ov5640_write_reg(sensor, reg_addr, val);
163619a81c14SSteve Longerbeam 		if (ret)
163719a81c14SSteve Longerbeam 			break;
163819a81c14SSteve Longerbeam 
163919a81c14SSteve Longerbeam 		if (delay_ms)
164019a81c14SSteve Longerbeam 			usleep_range(1000 * delay_ms, 1000 * delay_ms + 100);
164119a81c14SSteve Longerbeam 	}
164219a81c14SSteve Longerbeam 
1643bad1774eSJacopo Mondi 	return ov5640_set_timings(sensor, mode);
164419a81c14SSteve Longerbeam }
164519a81c14SSteve Longerbeam 
1646dc29a1c1SHugues Fruchet static int ov5640_set_autoexposure(struct ov5640_dev *sensor, bool on)
1647dc29a1c1SHugues Fruchet {
1648dc29a1c1SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
1649dc29a1c1SHugues Fruchet 			      BIT(0), on ? 0 : BIT(0));
1650dc29a1c1SHugues Fruchet }
1651dc29a1c1SHugues Fruchet 
165219a81c14SSteve Longerbeam /* read exposure, in number of line periods */
165319a81c14SSteve Longerbeam static int ov5640_get_exposure(struct ov5640_dev *sensor)
165419a81c14SSteve Longerbeam {
165519a81c14SSteve Longerbeam 	int exp, ret;
165619a81c14SSteve Longerbeam 	u8 temp;
165719a81c14SSteve Longerbeam 
165819a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_HI, &temp);
165919a81c14SSteve Longerbeam 	if (ret)
166019a81c14SSteve Longerbeam 		return ret;
166119a81c14SSteve Longerbeam 	exp = ((int)temp & 0x0f) << 16;
166219a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_MED, &temp);
166319a81c14SSteve Longerbeam 	if (ret)
166419a81c14SSteve Longerbeam 		return ret;
166519a81c14SSteve Longerbeam 	exp |= ((int)temp << 8);
166619a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_LO, &temp);
166719a81c14SSteve Longerbeam 	if (ret)
166819a81c14SSteve Longerbeam 		return ret;
166919a81c14SSteve Longerbeam 	exp |= (int)temp;
167019a81c14SSteve Longerbeam 
167119a81c14SSteve Longerbeam 	return exp >> 4;
167219a81c14SSteve Longerbeam }
167319a81c14SSteve Longerbeam 
167419a81c14SSteve Longerbeam /* write exposure, given number of line periods */
167519a81c14SSteve Longerbeam static int ov5640_set_exposure(struct ov5640_dev *sensor, u32 exposure)
167619a81c14SSteve Longerbeam {
167719a81c14SSteve Longerbeam 	int ret;
167819a81c14SSteve Longerbeam 
167919a81c14SSteve Longerbeam 	exposure <<= 4;
168019a81c14SSteve Longerbeam 
168119a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor,
168219a81c14SSteve Longerbeam 			       OV5640_REG_AEC_PK_EXPOSURE_LO,
168319a81c14SSteve Longerbeam 			       exposure & 0xff);
168419a81c14SSteve Longerbeam 	if (ret)
168519a81c14SSteve Longerbeam 		return ret;
168619a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor,
168719a81c14SSteve Longerbeam 			       OV5640_REG_AEC_PK_EXPOSURE_MED,
168819a81c14SSteve Longerbeam 			       (exposure >> 8) & 0xff);
168919a81c14SSteve Longerbeam 	if (ret)
169019a81c14SSteve Longerbeam 		return ret;
169119a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor,
169219a81c14SSteve Longerbeam 				OV5640_REG_AEC_PK_EXPOSURE_HI,
169319a81c14SSteve Longerbeam 				(exposure >> 16) & 0x0f);
169419a81c14SSteve Longerbeam }
169519a81c14SSteve Longerbeam 
169619a81c14SSteve Longerbeam static int ov5640_get_gain(struct ov5640_dev *sensor)
169719a81c14SSteve Longerbeam {
169819a81c14SSteve Longerbeam 	u16 gain;
169919a81c14SSteve Longerbeam 	int ret;
170019a81c14SSteve Longerbeam 
170119a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN, &gain);
170219a81c14SSteve Longerbeam 	if (ret)
170319a81c14SSteve Longerbeam 		return ret;
170419a81c14SSteve Longerbeam 
170519a81c14SSteve Longerbeam 	return gain & 0x3ff;
170619a81c14SSteve Longerbeam }
170719a81c14SSteve Longerbeam 
17083cca8ef5SHugues Fruchet static int ov5640_set_gain(struct ov5640_dev *sensor, int gain)
17093cca8ef5SHugues Fruchet {
17103cca8ef5SHugues Fruchet 	return ov5640_write_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN,
17113cca8ef5SHugues Fruchet 				  (u16)gain & 0x3ff);
17123cca8ef5SHugues Fruchet }
17133cca8ef5SHugues Fruchet 
17143cca8ef5SHugues Fruchet static int ov5640_set_autogain(struct ov5640_dev *sensor, bool on)
17153cca8ef5SHugues Fruchet {
17163cca8ef5SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
17173cca8ef5SHugues Fruchet 			      BIT(1), on ? 0 : BIT(1));
17183cca8ef5SHugues Fruchet }
17193cca8ef5SHugues Fruchet 
1720f22996dbSHugues Fruchet static int ov5640_set_stream_dvp(struct ov5640_dev *sensor, bool on)
1721f22996dbSHugues Fruchet {
17223b987d70SLad Prabhakar 	return ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0, on ?
17233b987d70SLad Prabhakar 				OV5640_REG_SYS_CTRL0_SW_PWUP :
17243b987d70SLad Prabhakar 				OV5640_REG_SYS_CTRL0_SW_PWDN);
1725f22996dbSHugues Fruchet }
1726f22996dbSHugues Fruchet 
1727f22996dbSHugues Fruchet static int ov5640_set_stream_mipi(struct ov5640_dev *sensor, bool on)
172819a81c14SSteve Longerbeam {
172919a81c14SSteve Longerbeam 	int ret;
173019a81c14SSteve Longerbeam 
1731aa4bb8b8SJacopo Mondi 	/*
1732aa4bb8b8SJacopo Mondi 	 * Enable/disable the MIPI interface
1733aa4bb8b8SJacopo Mondi 	 *
1734aa4bb8b8SJacopo Mondi 	 * 0x300e = on ? 0x45 : 0x40
1735aa4bb8b8SJacopo Mondi 	 *
1736aa4bb8b8SJacopo Mondi 	 * FIXME: the sensor manual (version 2.03) reports
1737aa4bb8b8SJacopo Mondi 	 * [7:5] = 000  : 1 data lane mode
1738aa4bb8b8SJacopo Mondi 	 * [7:5] = 001  : 2 data lanes mode
1739aa4bb8b8SJacopo Mondi 	 * But this settings do not work, while the following ones
1740aa4bb8b8SJacopo Mondi 	 * have been validated for 2 data lanes mode.
1741aa4bb8b8SJacopo Mondi 	 *
1742aa4bb8b8SJacopo Mondi 	 * [7:5] = 010	: 2 data lanes mode
1743aa4bb8b8SJacopo Mondi 	 * [4] = 0	: Power up MIPI HS Tx
1744aa4bb8b8SJacopo Mondi 	 * [3] = 0	: Power up MIPI LS Rx
1745aa4bb8b8SJacopo Mondi 	 * [2] = 1/0	: MIPI interface enable/disable
1746aa4bb8b8SJacopo Mondi 	 * [1:0] = 01/00: FIXME: 'debug'
1747aa4bb8b8SJacopo Mondi 	 */
1748aa4bb8b8SJacopo Mondi 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00,
1749aa4bb8b8SJacopo Mondi 			       on ? 0x45 : 0x40);
175019a81c14SSteve Longerbeam 	if (ret)
175119a81c14SSteve Longerbeam 		return ret;
175219a81c14SSteve Longerbeam 
175319a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_FRAME_CTRL01,
175419a81c14SSteve Longerbeam 				on ? 0x00 : 0x0f);
175519a81c14SSteve Longerbeam }
175619a81c14SSteve Longerbeam 
175719a81c14SSteve Longerbeam static int ov5640_get_sysclk(struct ov5640_dev *sensor)
175819a81c14SSteve Longerbeam {
175919a81c14SSteve Longerbeam 	 /* calculate sysclk */
176019a81c14SSteve Longerbeam 	u32 xvclk = sensor->xclk_freq / 10000;
176119a81c14SSteve Longerbeam 	u32 multiplier, prediv, VCO, sysdiv, pll_rdiv;
176219a81c14SSteve Longerbeam 	u32 sclk_rdiv_map[] = {1, 2, 4, 8};
176319a81c14SSteve Longerbeam 	u32 bit_div2x = 1, sclk_rdiv, sysclk;
176419a81c14SSteve Longerbeam 	u8 temp1, temp2;
176519a81c14SSteve Longerbeam 	int ret;
176619a81c14SSteve Longerbeam 
176719a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL0, &temp1);
176819a81c14SSteve Longerbeam 	if (ret)
176919a81c14SSteve Longerbeam 		return ret;
177019a81c14SSteve Longerbeam 	temp2 = temp1 & 0x0f;
177119a81c14SSteve Longerbeam 	if (temp2 == 8 || temp2 == 10)
177219a81c14SSteve Longerbeam 		bit_div2x = temp2 / 2;
177319a81c14SSteve Longerbeam 
177419a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL1, &temp1);
177519a81c14SSteve Longerbeam 	if (ret)
177619a81c14SSteve Longerbeam 		return ret;
177719a81c14SSteve Longerbeam 	sysdiv = temp1 >> 4;
177819a81c14SSteve Longerbeam 	if (sysdiv == 0)
177919a81c14SSteve Longerbeam 		sysdiv = 16;
178019a81c14SSteve Longerbeam 
178119a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL2, &temp1);
178219a81c14SSteve Longerbeam 	if (ret)
178319a81c14SSteve Longerbeam 		return ret;
178419a81c14SSteve Longerbeam 	multiplier = temp1;
178519a81c14SSteve Longerbeam 
178619a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL3, &temp1);
178719a81c14SSteve Longerbeam 	if (ret)
178819a81c14SSteve Longerbeam 		return ret;
178919a81c14SSteve Longerbeam 	prediv = temp1 & 0x0f;
179019a81c14SSteve Longerbeam 	pll_rdiv = ((temp1 >> 4) & 0x01) + 1;
179119a81c14SSteve Longerbeam 
179219a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, &temp1);
179319a81c14SSteve Longerbeam 	if (ret)
179419a81c14SSteve Longerbeam 		return ret;
179519a81c14SSteve Longerbeam 	temp2 = temp1 & 0x03;
179619a81c14SSteve Longerbeam 	sclk_rdiv = sclk_rdiv_map[temp2];
179719a81c14SSteve Longerbeam 
179819a81c14SSteve Longerbeam 	if (!prediv || !sysdiv || !pll_rdiv || !bit_div2x)
179919a81c14SSteve Longerbeam 		return -EINVAL;
180019a81c14SSteve Longerbeam 
180119a81c14SSteve Longerbeam 	VCO = xvclk * multiplier / prediv;
180219a81c14SSteve Longerbeam 
180319a81c14SSteve Longerbeam 	sysclk = VCO / sysdiv / pll_rdiv * 2 / bit_div2x / sclk_rdiv;
180419a81c14SSteve Longerbeam 
180519a81c14SSteve Longerbeam 	return sysclk;
180619a81c14SSteve Longerbeam }
180719a81c14SSteve Longerbeam 
180819a81c14SSteve Longerbeam static int ov5640_set_night_mode(struct ov5640_dev *sensor)
180919a81c14SSteve Longerbeam {
181019a81c14SSteve Longerbeam 	 /* read HTS from register settings */
181119a81c14SSteve Longerbeam 	u8 mode;
181219a81c14SSteve Longerbeam 	int ret;
181319a81c14SSteve Longerbeam 
181419a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_CTRL00, &mode);
181519a81c14SSteve Longerbeam 	if (ret)
181619a81c14SSteve Longerbeam 		return ret;
181719a81c14SSteve Longerbeam 	mode &= 0xfb;
181819a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL00, mode);
181919a81c14SSteve Longerbeam }
182019a81c14SSteve Longerbeam 
182119a81c14SSteve Longerbeam static int ov5640_get_hts(struct ov5640_dev *sensor)
182219a81c14SSteve Longerbeam {
182319a81c14SSteve Longerbeam 	/* read HTS from register settings */
182419a81c14SSteve Longerbeam 	u16 hts;
182519a81c14SSteve Longerbeam 	int ret;
182619a81c14SSteve Longerbeam 
182719a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_HTS, &hts);
182819a81c14SSteve Longerbeam 	if (ret)
182919a81c14SSteve Longerbeam 		return ret;
183019a81c14SSteve Longerbeam 	return hts;
183119a81c14SSteve Longerbeam }
183219a81c14SSteve Longerbeam 
183319a81c14SSteve Longerbeam static int ov5640_get_vts(struct ov5640_dev *sensor)
183419a81c14SSteve Longerbeam {
183519a81c14SSteve Longerbeam 	u16 vts;
183619a81c14SSteve Longerbeam 	int ret;
183719a81c14SSteve Longerbeam 
183819a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_VTS, &vts);
183919a81c14SSteve Longerbeam 	if (ret)
184019a81c14SSteve Longerbeam 		return ret;
184119a81c14SSteve Longerbeam 	return vts;
184219a81c14SSteve Longerbeam }
184319a81c14SSteve Longerbeam 
184419a81c14SSteve Longerbeam static int ov5640_set_vts(struct ov5640_dev *sensor, int vts)
184519a81c14SSteve Longerbeam {
184619a81c14SSteve Longerbeam 	return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, vts);
184719a81c14SSteve Longerbeam }
184819a81c14SSteve Longerbeam 
184919a81c14SSteve Longerbeam static int ov5640_get_light_freq(struct ov5640_dev *sensor)
185019a81c14SSteve Longerbeam {
185119a81c14SSteve Longerbeam 	/* get banding filter value */
185219a81c14SSteve Longerbeam 	int ret, light_freq = 0;
185319a81c14SSteve Longerbeam 	u8 temp, temp1;
185419a81c14SSteve Longerbeam 
185519a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL01, &temp);
185619a81c14SSteve Longerbeam 	if (ret)
185719a81c14SSteve Longerbeam 		return ret;
185819a81c14SSteve Longerbeam 
185919a81c14SSteve Longerbeam 	if (temp & 0x80) {
186019a81c14SSteve Longerbeam 		/* manual */
186119a81c14SSteve Longerbeam 		ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL00,
186219a81c14SSteve Longerbeam 				      &temp1);
186319a81c14SSteve Longerbeam 		if (ret)
186419a81c14SSteve Longerbeam 			return ret;
186519a81c14SSteve Longerbeam 		if (temp1 & 0x04) {
186619a81c14SSteve Longerbeam 			/* 50Hz */
186719a81c14SSteve Longerbeam 			light_freq = 50;
186819a81c14SSteve Longerbeam 		} else {
186919a81c14SSteve Longerbeam 			/* 60Hz */
187019a81c14SSteve Longerbeam 			light_freq = 60;
187119a81c14SSteve Longerbeam 		}
187219a81c14SSteve Longerbeam 	} else {
187319a81c14SSteve Longerbeam 		/* auto */
187419a81c14SSteve Longerbeam 		ret = ov5640_read_reg(sensor, OV5640_REG_SIGMADELTA_CTRL0C,
187519a81c14SSteve Longerbeam 				      &temp1);
187619a81c14SSteve Longerbeam 		if (ret)
187719a81c14SSteve Longerbeam 			return ret;
187819a81c14SSteve Longerbeam 
187919a81c14SSteve Longerbeam 		if (temp1 & 0x01) {
188019a81c14SSteve Longerbeam 			/* 50Hz */
188119a81c14SSteve Longerbeam 			light_freq = 50;
188219a81c14SSteve Longerbeam 		} else {
188319a81c14SSteve Longerbeam 			/* 60Hz */
188419a81c14SSteve Longerbeam 		}
188519a81c14SSteve Longerbeam 	}
188619a81c14SSteve Longerbeam 
188719a81c14SSteve Longerbeam 	return light_freq;
188819a81c14SSteve Longerbeam }
188919a81c14SSteve Longerbeam 
189019a81c14SSteve Longerbeam static int ov5640_set_bandingfilter(struct ov5640_dev *sensor)
189119a81c14SSteve Longerbeam {
189219a81c14SSteve Longerbeam 	u32 band_step60, max_band60, band_step50, max_band50, prev_vts;
189319a81c14SSteve Longerbeam 	int ret;
189419a81c14SSteve Longerbeam 
189519a81c14SSteve Longerbeam 	/* read preview PCLK */
189619a81c14SSteve Longerbeam 	ret = ov5640_get_sysclk(sensor);
189719a81c14SSteve Longerbeam 	if (ret < 0)
189819a81c14SSteve Longerbeam 		return ret;
189919a81c14SSteve Longerbeam 	if (ret == 0)
190019a81c14SSteve Longerbeam 		return -EINVAL;
190119a81c14SSteve Longerbeam 	sensor->prev_sysclk = ret;
190219a81c14SSteve Longerbeam 	/* read preview HTS */
190319a81c14SSteve Longerbeam 	ret = ov5640_get_hts(sensor);
190419a81c14SSteve Longerbeam 	if (ret < 0)
190519a81c14SSteve Longerbeam 		return ret;
190619a81c14SSteve Longerbeam 	if (ret == 0)
190719a81c14SSteve Longerbeam 		return -EINVAL;
190819a81c14SSteve Longerbeam 	sensor->prev_hts = ret;
190919a81c14SSteve Longerbeam 
191019a81c14SSteve Longerbeam 	/* read preview VTS */
191119a81c14SSteve Longerbeam 	ret = ov5640_get_vts(sensor);
191219a81c14SSteve Longerbeam 	if (ret < 0)
191319a81c14SSteve Longerbeam 		return ret;
191419a81c14SSteve Longerbeam 	prev_vts = ret;
191519a81c14SSteve Longerbeam 
191619a81c14SSteve Longerbeam 	/* calculate banding filter */
191719a81c14SSteve Longerbeam 	/* 60Hz */
191819a81c14SSteve Longerbeam 	band_step60 = sensor->prev_sysclk * 100 / sensor->prev_hts * 100 / 120;
191919a81c14SSteve Longerbeam 	ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B60_STEP, band_step60);
192019a81c14SSteve Longerbeam 	if (ret)
192119a81c14SSteve Longerbeam 		return ret;
192219a81c14SSteve Longerbeam 	if (!band_step60)
192319a81c14SSteve Longerbeam 		return -EINVAL;
192419a81c14SSteve Longerbeam 	max_band60 = (int)((prev_vts - 4) / band_step60);
192519a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0D, max_band60);
192619a81c14SSteve Longerbeam 	if (ret)
192719a81c14SSteve Longerbeam 		return ret;
192819a81c14SSteve Longerbeam 
192919a81c14SSteve Longerbeam 	/* 50Hz */
193019a81c14SSteve Longerbeam 	band_step50 = sensor->prev_sysclk * 100 / sensor->prev_hts;
193119a81c14SSteve Longerbeam 	ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B50_STEP, band_step50);
193219a81c14SSteve Longerbeam 	if (ret)
193319a81c14SSteve Longerbeam 		return ret;
193419a81c14SSteve Longerbeam 	if (!band_step50)
193519a81c14SSteve Longerbeam 		return -EINVAL;
193619a81c14SSteve Longerbeam 	max_band50 = (int)((prev_vts - 4) / band_step50);
193719a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0E, max_band50);
193819a81c14SSteve Longerbeam }
193919a81c14SSteve Longerbeam 
194019a81c14SSteve Longerbeam static int ov5640_set_ae_target(struct ov5640_dev *sensor, int target)
194119a81c14SSteve Longerbeam {
194219a81c14SSteve Longerbeam 	/* stable in high */
194319a81c14SSteve Longerbeam 	u32 fast_high, fast_low;
194419a81c14SSteve Longerbeam 	int ret;
194519a81c14SSteve Longerbeam 
194619a81c14SSteve Longerbeam 	sensor->ae_low = target * 23 / 25;	/* 0.92 */
194719a81c14SSteve Longerbeam 	sensor->ae_high = target * 27 / 25;	/* 1.08 */
194819a81c14SSteve Longerbeam 
194919a81c14SSteve Longerbeam 	fast_high = sensor->ae_high << 1;
195019a81c14SSteve Longerbeam 	if (fast_high > 255)
195119a81c14SSteve Longerbeam 		fast_high = 255;
195219a81c14SSteve Longerbeam 
195319a81c14SSteve Longerbeam 	fast_low = sensor->ae_low >> 1;
195419a81c14SSteve Longerbeam 
195519a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0F, sensor->ae_high);
195619a81c14SSteve Longerbeam 	if (ret)
195719a81c14SSteve Longerbeam 		return ret;
195819a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL10, sensor->ae_low);
195919a81c14SSteve Longerbeam 	if (ret)
196019a81c14SSteve Longerbeam 		return ret;
196119a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1B, sensor->ae_high);
196219a81c14SSteve Longerbeam 	if (ret)
196319a81c14SSteve Longerbeam 		return ret;
196419a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1E, sensor->ae_low);
196519a81c14SSteve Longerbeam 	if (ret)
196619a81c14SSteve Longerbeam 		return ret;
196719a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL11, fast_high);
196819a81c14SSteve Longerbeam 	if (ret)
196919a81c14SSteve Longerbeam 		return ret;
197019a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1F, fast_low);
197119a81c14SSteve Longerbeam }
197219a81c14SSteve Longerbeam 
1973c2c3f42dSHugues Fruchet static int ov5640_get_binning(struct ov5640_dev *sensor)
197419a81c14SSteve Longerbeam {
197519a81c14SSteve Longerbeam 	u8 temp;
197619a81c14SSteve Longerbeam 	int ret;
197719a81c14SSteve Longerbeam 
197819a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_TIMING_TC_REG21, &temp);
197919a81c14SSteve Longerbeam 	if (ret)
198019a81c14SSteve Longerbeam 		return ret;
1981c2c3f42dSHugues Fruchet 
1982c2c3f42dSHugues Fruchet 	return temp & BIT(0);
198319a81c14SSteve Longerbeam }
198419a81c14SSteve Longerbeam 
1985ce85705aSHugues Fruchet static int ov5640_set_binning(struct ov5640_dev *sensor, bool enable)
1986ce85705aSHugues Fruchet {
1987ce85705aSHugues Fruchet 	int ret;
1988ce85705aSHugues Fruchet 
1989ce85705aSHugues Fruchet 	/*
1990ce85705aSHugues Fruchet 	 * TIMING TC REG21:
1991ce85705aSHugues Fruchet 	 * - [0]:	Horizontal binning enable
1992ce85705aSHugues Fruchet 	 */
1993ce85705aSHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
1994ce85705aSHugues Fruchet 			     BIT(0), enable ? BIT(0) : 0);
1995ce85705aSHugues Fruchet 	if (ret)
1996ce85705aSHugues Fruchet 		return ret;
1997ce85705aSHugues Fruchet 	/*
1998ce85705aSHugues Fruchet 	 * TIMING TC REG20:
1999ce85705aSHugues Fruchet 	 * - [0]:	Undocumented, but hardcoded init sequences
2000ce85705aSHugues Fruchet 	 *		are always setting REG21/REG20 bit 0 to same value...
2001ce85705aSHugues Fruchet 	 */
2002ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20,
2003ce85705aSHugues Fruchet 			      BIT(0), enable ? BIT(0) : 0);
2004ce85705aSHugues Fruchet }
2005ce85705aSHugues Fruchet 
200619a81c14SSteve Longerbeam static int ov5640_set_virtual_channel(struct ov5640_dev *sensor)
200719a81c14SSteve Longerbeam {
20088670d70aSHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
200919a81c14SSteve Longerbeam 	u8 temp, channel = virtual_channel;
201019a81c14SSteve Longerbeam 	int ret;
201119a81c14SSteve Longerbeam 
20128670d70aSHugues Fruchet 	if (channel > 3) {
20138670d70aSHugues Fruchet 		dev_err(&client->dev,
20148670d70aSHugues Fruchet 			"%s: wrong virtual_channel parameter, expected (0..3), got %d\n",
20158670d70aSHugues Fruchet 			__func__, channel);
201619a81c14SSteve Longerbeam 		return -EINVAL;
20178670d70aSHugues Fruchet 	}
201819a81c14SSteve Longerbeam 
201919a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_DEBUG_MODE, &temp);
202019a81c14SSteve Longerbeam 	if (ret)
202119a81c14SSteve Longerbeam 		return ret;
202219a81c14SSteve Longerbeam 	temp &= ~(3 << 6);
202319a81c14SSteve Longerbeam 	temp |= (channel << 6);
202419a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_DEBUG_MODE, temp);
202519a81c14SSteve Longerbeam }
202619a81c14SSteve Longerbeam 
202719a81c14SSteve Longerbeam static const struct ov5640_mode_info *
202819a81c14SSteve Longerbeam ov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr,
202919a81c14SSteve Longerbeam 		 int width, int height, bool nearest)
203019a81c14SSteve Longerbeam {
20313c4a7372SHugues Fruchet 	const struct ov5640_mode_info *mode;
203219a81c14SSteve Longerbeam 
2033086c25f8SMaxime Ripard 	mode = v4l2_find_nearest_size(ov5640_mode_data,
2034086c25f8SMaxime Ripard 				      ARRAY_SIZE(ov5640_mode_data),
20355113d5b3SJacopo Mondi 				      width, height, width, height);
203619a81c14SSteve Longerbeam 
20373c4a7372SHugues Fruchet 	if (!mode ||
20383145efcdSJacopo Mondi 	    (!nearest &&
20395113d5b3SJacopo Mondi 	     (mode->width != width || mode->height != height)))
20403c4a7372SHugues Fruchet 		return NULL;
204119a81c14SSteve Longerbeam 
20425554c80eSAdam Ford 	/* Check to see if the current mode exceeds the max frame rate */
20435554c80eSAdam Ford 	if (ov5640_framerates[fr] > ov5640_framerates[mode->max_fps])
2044981e4454SBenoit Parrot 		return NULL;
2045981e4454SBenoit Parrot 
204619a81c14SSteve Longerbeam 	return mode;
204719a81c14SSteve Longerbeam }
204819a81c14SSteve Longerbeam 
204919a81c14SSteve Longerbeam /*
205019a81c14SSteve Longerbeam  * sensor changes between scaling and subsampling, go through
205119a81c14SSteve Longerbeam  * exposure calculation
205219a81c14SSteve Longerbeam  */
205341d8d7f5SHugues Fruchet static int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor,
205441d8d7f5SHugues Fruchet 					 const struct ov5640_mode_info *mode)
205519a81c14SSteve Longerbeam {
205619a81c14SSteve Longerbeam 	u32 prev_shutter, prev_gain16;
205719a81c14SSteve Longerbeam 	u32 cap_shutter, cap_gain16;
205819a81c14SSteve Longerbeam 	u32 cap_sysclk, cap_hts, cap_vts;
205919a81c14SSteve Longerbeam 	u32 light_freq, cap_bandfilt, cap_maxband;
206019a81c14SSteve Longerbeam 	u32 cap_gain16_shutter;
206119a81c14SSteve Longerbeam 	u8 average;
206219a81c14SSteve Longerbeam 	int ret;
206319a81c14SSteve Longerbeam 
206441d8d7f5SHugues Fruchet 	if (!mode->reg_data)
206519a81c14SSteve Longerbeam 		return -EINVAL;
206619a81c14SSteve Longerbeam 
206719a81c14SSteve Longerbeam 	/* read preview shutter */
206819a81c14SSteve Longerbeam 	ret = ov5640_get_exposure(sensor);
206919a81c14SSteve Longerbeam 	if (ret < 0)
207019a81c14SSteve Longerbeam 		return ret;
207119a81c14SSteve Longerbeam 	prev_shutter = ret;
2072c2c3f42dSHugues Fruchet 	ret = ov5640_get_binning(sensor);
207319a81c14SSteve Longerbeam 	if (ret < 0)
207419a81c14SSteve Longerbeam 		return ret;
207519a81c14SSteve Longerbeam 	if (ret && mode->id != OV5640_MODE_720P_1280_720 &&
207619a81c14SSteve Longerbeam 	    mode->id != OV5640_MODE_1080P_1920_1080)
207719a81c14SSteve Longerbeam 		prev_shutter *= 2;
207819a81c14SSteve Longerbeam 
207919a81c14SSteve Longerbeam 	/* read preview gain */
208019a81c14SSteve Longerbeam 	ret = ov5640_get_gain(sensor);
208119a81c14SSteve Longerbeam 	if (ret < 0)
208219a81c14SSteve Longerbeam 		return ret;
208319a81c14SSteve Longerbeam 	prev_gain16 = ret;
208419a81c14SSteve Longerbeam 
208519a81c14SSteve Longerbeam 	/* get average */
208619a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AVG_READOUT, &average);
208719a81c14SSteve Longerbeam 	if (ret)
208819a81c14SSteve Longerbeam 		return ret;
208919a81c14SSteve Longerbeam 
209019a81c14SSteve Longerbeam 	/* turn off night mode for capture */
209119a81c14SSteve Longerbeam 	ret = ov5640_set_night_mode(sensor);
209219a81c14SSteve Longerbeam 	if (ret < 0)
209319a81c14SSteve Longerbeam 		return ret;
209419a81c14SSteve Longerbeam 
209519a81c14SSteve Longerbeam 	/* Write capture setting */
209619a81c14SSteve Longerbeam 	ret = ov5640_load_regs(sensor, mode);
209719a81c14SSteve Longerbeam 	if (ret < 0)
209819a81c14SSteve Longerbeam 		return ret;
209919a81c14SSteve Longerbeam 
210019a81c14SSteve Longerbeam 	/* read capture VTS */
210119a81c14SSteve Longerbeam 	ret = ov5640_get_vts(sensor);
210219a81c14SSteve Longerbeam 	if (ret < 0)
210319a81c14SSteve Longerbeam 		return ret;
210419a81c14SSteve Longerbeam 	cap_vts = ret;
210519a81c14SSteve Longerbeam 	ret = ov5640_get_hts(sensor);
210619a81c14SSteve Longerbeam 	if (ret < 0)
210719a81c14SSteve Longerbeam 		return ret;
210819a81c14SSteve Longerbeam 	if (ret == 0)
210919a81c14SSteve Longerbeam 		return -EINVAL;
211019a81c14SSteve Longerbeam 	cap_hts = ret;
211119a81c14SSteve Longerbeam 
211219a81c14SSteve Longerbeam 	ret = ov5640_get_sysclk(sensor);
211319a81c14SSteve Longerbeam 	if (ret < 0)
211419a81c14SSteve Longerbeam 		return ret;
211519a81c14SSteve Longerbeam 	if (ret == 0)
211619a81c14SSteve Longerbeam 		return -EINVAL;
211719a81c14SSteve Longerbeam 	cap_sysclk = ret;
211819a81c14SSteve Longerbeam 
211919a81c14SSteve Longerbeam 	/* calculate capture banding filter */
212019a81c14SSteve Longerbeam 	ret = ov5640_get_light_freq(sensor);
212119a81c14SSteve Longerbeam 	if (ret < 0)
212219a81c14SSteve Longerbeam 		return ret;
212319a81c14SSteve Longerbeam 	light_freq = ret;
212419a81c14SSteve Longerbeam 
212519a81c14SSteve Longerbeam 	if (light_freq == 60) {
212619a81c14SSteve Longerbeam 		/* 60Hz */
212719a81c14SSteve Longerbeam 		cap_bandfilt = cap_sysclk * 100 / cap_hts * 100 / 120;
212819a81c14SSteve Longerbeam 	} else {
212919a81c14SSteve Longerbeam 		/* 50Hz */
213019a81c14SSteve Longerbeam 		cap_bandfilt = cap_sysclk * 100 / cap_hts;
213119a81c14SSteve Longerbeam 	}
213219a81c14SSteve Longerbeam 
213319a81c14SSteve Longerbeam 	if (!sensor->prev_sysclk) {
213419a81c14SSteve Longerbeam 		ret = ov5640_get_sysclk(sensor);
213519a81c14SSteve Longerbeam 		if (ret < 0)
213619a81c14SSteve Longerbeam 			return ret;
213719a81c14SSteve Longerbeam 		if (ret == 0)
213819a81c14SSteve Longerbeam 			return -EINVAL;
213919a81c14SSteve Longerbeam 		sensor->prev_sysclk = ret;
214019a81c14SSteve Longerbeam 	}
214119a81c14SSteve Longerbeam 
214219a81c14SSteve Longerbeam 	if (!cap_bandfilt)
214319a81c14SSteve Longerbeam 		return -EINVAL;
214419a81c14SSteve Longerbeam 
214519a81c14SSteve Longerbeam 	cap_maxband = (int)((cap_vts - 4) / cap_bandfilt);
214619a81c14SSteve Longerbeam 
214719a81c14SSteve Longerbeam 	/* calculate capture shutter/gain16 */
214819a81c14SSteve Longerbeam 	if (average > sensor->ae_low && average < sensor->ae_high) {
214919a81c14SSteve Longerbeam 		/* in stable range */
215019a81c14SSteve Longerbeam 		cap_gain16_shutter =
215119a81c14SSteve Longerbeam 			prev_gain16 * prev_shutter *
215219a81c14SSteve Longerbeam 			cap_sysclk / sensor->prev_sysclk *
215319a81c14SSteve Longerbeam 			sensor->prev_hts / cap_hts *
215419a81c14SSteve Longerbeam 			sensor->ae_target / average;
215519a81c14SSteve Longerbeam 	} else {
215619a81c14SSteve Longerbeam 		cap_gain16_shutter =
215719a81c14SSteve Longerbeam 			prev_gain16 * prev_shutter *
215819a81c14SSteve Longerbeam 			cap_sysclk / sensor->prev_sysclk *
215919a81c14SSteve Longerbeam 			sensor->prev_hts / cap_hts;
216019a81c14SSteve Longerbeam 	}
216119a81c14SSteve Longerbeam 
216219a81c14SSteve Longerbeam 	/* gain to shutter */
216319a81c14SSteve Longerbeam 	if (cap_gain16_shutter < (cap_bandfilt * 16)) {
216419a81c14SSteve Longerbeam 		/* shutter < 1/100 */
216519a81c14SSteve Longerbeam 		cap_shutter = cap_gain16_shutter / 16;
216619a81c14SSteve Longerbeam 		if (cap_shutter < 1)
216719a81c14SSteve Longerbeam 			cap_shutter = 1;
216819a81c14SSteve Longerbeam 
216919a81c14SSteve Longerbeam 		cap_gain16 = cap_gain16_shutter / cap_shutter;
217019a81c14SSteve Longerbeam 		if (cap_gain16 < 16)
217119a81c14SSteve Longerbeam 			cap_gain16 = 16;
217219a81c14SSteve Longerbeam 	} else {
217319a81c14SSteve Longerbeam 		if (cap_gain16_shutter > (cap_bandfilt * cap_maxband * 16)) {
217419a81c14SSteve Longerbeam 			/* exposure reach max */
217519a81c14SSteve Longerbeam 			cap_shutter = cap_bandfilt * cap_maxband;
217619a81c14SSteve Longerbeam 			if (!cap_shutter)
217719a81c14SSteve Longerbeam 				return -EINVAL;
217819a81c14SSteve Longerbeam 
217919a81c14SSteve Longerbeam 			cap_gain16 = cap_gain16_shutter / cap_shutter;
218019a81c14SSteve Longerbeam 		} else {
218119a81c14SSteve Longerbeam 			/* 1/100 < (cap_shutter = n/100) =< max */
218219a81c14SSteve Longerbeam 			cap_shutter =
218319a81c14SSteve Longerbeam 				((int)(cap_gain16_shutter / 16 / cap_bandfilt))
218419a81c14SSteve Longerbeam 				* cap_bandfilt;
218519a81c14SSteve Longerbeam 			if (!cap_shutter)
218619a81c14SSteve Longerbeam 				return -EINVAL;
218719a81c14SSteve Longerbeam 
218819a81c14SSteve Longerbeam 			cap_gain16 = cap_gain16_shutter / cap_shutter;
218919a81c14SSteve Longerbeam 		}
219019a81c14SSteve Longerbeam 	}
219119a81c14SSteve Longerbeam 
219219a81c14SSteve Longerbeam 	/* set capture gain */
21933cca8ef5SHugues Fruchet 	ret = ov5640_set_gain(sensor, cap_gain16);
219419a81c14SSteve Longerbeam 	if (ret)
219519a81c14SSteve Longerbeam 		return ret;
219619a81c14SSteve Longerbeam 
219719a81c14SSteve Longerbeam 	/* write capture shutter */
219819a81c14SSteve Longerbeam 	if (cap_shutter > (cap_vts - 4)) {
219919a81c14SSteve Longerbeam 		cap_vts = cap_shutter + 4;
220019a81c14SSteve Longerbeam 		ret = ov5640_set_vts(sensor, cap_vts);
220119a81c14SSteve Longerbeam 		if (ret < 0)
220219a81c14SSteve Longerbeam 			return ret;
220319a81c14SSteve Longerbeam 	}
220419a81c14SSteve Longerbeam 
220519a81c14SSteve Longerbeam 	/* set exposure */
22063cca8ef5SHugues Fruchet 	return ov5640_set_exposure(sensor, cap_shutter);
220719a81c14SSteve Longerbeam }
220819a81c14SSteve Longerbeam 
220919a81c14SSteve Longerbeam /*
221019a81c14SSteve Longerbeam  * if sensor changes inside scaling or subsampling
221119a81c14SSteve Longerbeam  * change mode directly
221219a81c14SSteve Longerbeam  */
221319a81c14SSteve Longerbeam static int ov5640_set_mode_direct(struct ov5640_dev *sensor,
22143cca8ef5SHugues Fruchet 				  const struct ov5640_mode_info *mode)
221519a81c14SSteve Longerbeam {
221641d8d7f5SHugues Fruchet 	if (!mode->reg_data)
221719a81c14SSteve Longerbeam 		return -EINVAL;
221819a81c14SSteve Longerbeam 
221919a81c14SSteve Longerbeam 	/* Write capture setting */
22203cca8ef5SHugues Fruchet 	return ov5640_load_regs(sensor, mode);
222119a81c14SSteve Longerbeam }
222219a81c14SSteve Longerbeam 
2223985cdcb0SHugues Fruchet static int ov5640_set_mode(struct ov5640_dev *sensor)
222419a81c14SSteve Longerbeam {
222519a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode = sensor->current_mode;
2226985cdcb0SHugues Fruchet 	const struct ov5640_mode_info *orig_mode = sensor->last_mode;
222719a81c14SSteve Longerbeam 	enum ov5640_downsize_mode dn_mode, orig_dn_mode;
22283cca8ef5SHugues Fruchet 	bool auto_gain = sensor->ctrls.auto_gain->val == 1;
2229dc29a1c1SHugues Fruchet 	bool auto_exp =  sensor->ctrls.auto_exp->val == V4L2_EXPOSURE_AUTO;
223019a81c14SSteve Longerbeam 	int ret;
223119a81c14SSteve Longerbeam 
223219a81c14SSteve Longerbeam 	dn_mode = mode->dn_mode;
223319a81c14SSteve Longerbeam 	orig_dn_mode = orig_mode->dn_mode;
223419a81c14SSteve Longerbeam 
223519a81c14SSteve Longerbeam 	/* auto gain and exposure must be turned off when changing modes */
22363cca8ef5SHugues Fruchet 	if (auto_gain) {
22373cca8ef5SHugues Fruchet 		ret = ov5640_set_autogain(sensor, false);
223819a81c14SSteve Longerbeam 		if (ret)
223919a81c14SSteve Longerbeam 			return ret;
22403cca8ef5SHugues Fruchet 	}
2241bf4a4b51SMaxime Ripard 
22423cca8ef5SHugues Fruchet 	if (auto_exp) {
2243dc29a1c1SHugues Fruchet 		ret = ov5640_set_autoexposure(sensor, false);
224419a81c14SSteve Longerbeam 		if (ret)
22453cca8ef5SHugues Fruchet 			goto restore_auto_gain;
22463cca8ef5SHugues Fruchet 	}
224719a81c14SSteve Longerbeam 
22486c957ed7SJacopo Mondi 	if (ov5640_is_csi2(sensor))
22496c957ed7SJacopo Mondi 		ret = ov5640_set_mipi_pclk(sensor);
22506c957ed7SJacopo Mondi 	else
22516c957ed7SJacopo Mondi 		ret = ov5640_set_dvp_pclk(sensor);
2252aa288248SMaxime Ripard 	if (ret < 0)
2253aa288248SMaxime Ripard 		return 0;
2254aa288248SMaxime Ripard 
225519a81c14SSteve Longerbeam 	if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) ||
225619a81c14SSteve Longerbeam 	    (dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) {
225719a81c14SSteve Longerbeam 		/*
225819a81c14SSteve Longerbeam 		 * change between subsampling and scaling
22593cca8ef5SHugues Fruchet 		 * go through exposure calculation
226019a81c14SSteve Longerbeam 		 */
226119a81c14SSteve Longerbeam 		ret = ov5640_set_mode_exposure_calc(sensor, mode);
226219a81c14SSteve Longerbeam 	} else {
226319a81c14SSteve Longerbeam 		/*
226419a81c14SSteve Longerbeam 		 * change inside subsampling or scaling
226519a81c14SSteve Longerbeam 		 * download firmware directly
226619a81c14SSteve Longerbeam 		 */
22673cca8ef5SHugues Fruchet 		ret = ov5640_set_mode_direct(sensor, mode);
226819a81c14SSteve Longerbeam 	}
226919a81c14SSteve Longerbeam 	if (ret < 0)
22703cca8ef5SHugues Fruchet 		goto restore_auto_exp_gain;
22713cca8ef5SHugues Fruchet 
22723cca8ef5SHugues Fruchet 	/* restore auto gain and exposure */
22733cca8ef5SHugues Fruchet 	if (auto_gain)
22743cca8ef5SHugues Fruchet 		ov5640_set_autogain(sensor, true);
22753cca8ef5SHugues Fruchet 	if (auto_exp)
22763cca8ef5SHugues Fruchet 		ov5640_set_autoexposure(sensor, true);
227719a81c14SSteve Longerbeam 
2278ce85705aSHugues Fruchet 	ret = ov5640_set_binning(sensor, dn_mode != SCALING);
2279ce85705aSHugues Fruchet 	if (ret < 0)
2280ce85705aSHugues Fruchet 		return ret;
228119a81c14SSteve Longerbeam 	ret = ov5640_set_ae_target(sensor, sensor->ae_target);
228219a81c14SSteve Longerbeam 	if (ret < 0)
228319a81c14SSteve Longerbeam 		return ret;
228419a81c14SSteve Longerbeam 	ret = ov5640_get_light_freq(sensor);
228519a81c14SSteve Longerbeam 	if (ret < 0)
228619a81c14SSteve Longerbeam 		return ret;
228719a81c14SSteve Longerbeam 	ret = ov5640_set_bandingfilter(sensor);
228819a81c14SSteve Longerbeam 	if (ret < 0)
228919a81c14SSteve Longerbeam 		return ret;
229019a81c14SSteve Longerbeam 	ret = ov5640_set_virtual_channel(sensor);
229119a81c14SSteve Longerbeam 	if (ret < 0)
229219a81c14SSteve Longerbeam 		return ret;
229319a81c14SSteve Longerbeam 
229419a81c14SSteve Longerbeam 	sensor->pending_mode_change = false;
2295985cdcb0SHugues Fruchet 	sensor->last_mode = mode;
229619a81c14SSteve Longerbeam 
229719a81c14SSteve Longerbeam 	return 0;
22983cca8ef5SHugues Fruchet 
22993cca8ef5SHugues Fruchet restore_auto_exp_gain:
23003cca8ef5SHugues Fruchet 	if (auto_exp)
23013cca8ef5SHugues Fruchet 		ov5640_set_autoexposure(sensor, true);
23023cca8ef5SHugues Fruchet restore_auto_gain:
23033cca8ef5SHugues Fruchet 	if (auto_gain)
23043cca8ef5SHugues Fruchet 		ov5640_set_autogain(sensor, true);
23053cca8ef5SHugues Fruchet 
23063cca8ef5SHugues Fruchet 	return ret;
230719a81c14SSteve Longerbeam }
230819a81c14SSteve Longerbeam 
230919ad26f9SAkinobu Mita static int ov5640_set_framefmt(struct ov5640_dev *sensor,
231019ad26f9SAkinobu Mita 			       struct v4l2_mbus_framefmt *format);
231119ad26f9SAkinobu Mita 
231219a81c14SSteve Longerbeam /* restore the last set video mode after chip power-on */
231319a81c14SSteve Longerbeam static int ov5640_restore_mode(struct ov5640_dev *sensor)
231419a81c14SSteve Longerbeam {
231519a81c14SSteve Longerbeam 	int ret;
231619a81c14SSteve Longerbeam 
231719a81c14SSteve Longerbeam 	/* first load the initial register values */
231819a81c14SSteve Longerbeam 	ret = ov5640_load_regs(sensor, &ov5640_mode_init_data);
231919a81c14SSteve Longerbeam 	if (ret < 0)
232019a81c14SSteve Longerbeam 		return ret;
2321985cdcb0SHugues Fruchet 	sensor->last_mode = &ov5640_mode_init_data;
232219a81c14SSteve Longerbeam 
23238f57c2f8SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
23247851fe7aSMaxime Ripard 			     (ilog2(OV5640_SCLK2X_ROOT_DIV) << 2) |
23257851fe7aSMaxime Ripard 			     ilog2(OV5640_SCLK_ROOT_DIV));
23268f57c2f8SMaxime Ripard 	if (ret)
23278f57c2f8SMaxime Ripard 		return ret;
23288f57c2f8SMaxime Ripard 
232919a81c14SSteve Longerbeam 	/* now restore the last capture mode */
2330985cdcb0SHugues Fruchet 	ret = ov5640_set_mode(sensor);
233119ad26f9SAkinobu Mita 	if (ret < 0)
233219ad26f9SAkinobu Mita 		return ret;
233319ad26f9SAkinobu Mita 
233419ad26f9SAkinobu Mita 	return ov5640_set_framefmt(sensor, &sensor->fmt);
233519a81c14SSteve Longerbeam }
233619a81c14SSteve Longerbeam 
233719a81c14SSteve Longerbeam static void ov5640_power(struct ov5640_dev *sensor, bool enable)
233819a81c14SSteve Longerbeam {
23391fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->pwdn_gpio, enable ? 0 : 1);
234019a81c14SSteve Longerbeam }
234119a81c14SSteve Longerbeam 
234219a81c14SSteve Longerbeam static void ov5640_reset(struct ov5640_dev *sensor)
234319a81c14SSteve Longerbeam {
234419a81c14SSteve Longerbeam 	if (!sensor->reset_gpio)
234519a81c14SSteve Longerbeam 		return;
234619a81c14SSteve Longerbeam 
23471fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 0);
234819a81c14SSteve Longerbeam 
234919a81c14SSteve Longerbeam 	/* camera power cycle */
235019a81c14SSteve Longerbeam 	ov5640_power(sensor, false);
235119a81c14SSteve Longerbeam 	usleep_range(5000, 10000);
235219a81c14SSteve Longerbeam 	ov5640_power(sensor, true);
235319a81c14SSteve Longerbeam 	usleep_range(5000, 10000);
235419a81c14SSteve Longerbeam 
23551fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 1);
235619a81c14SSteve Longerbeam 	usleep_range(1000, 2000);
235719a81c14SSteve Longerbeam 
23581fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 0);
23591d4c41f3SLoic Poulain 	usleep_range(20000, 25000);
236019a81c14SSteve Longerbeam }
236119a81c14SSteve Longerbeam 
23620f7acb52SHugues Fruchet static int ov5640_set_power_on(struct ov5640_dev *sensor)
236319a81c14SSteve Longerbeam {
23640f7acb52SHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
23650f7acb52SHugues Fruchet 	int ret;
236619a81c14SSteve Longerbeam 
23670f7acb52SHugues Fruchet 	ret = clk_prepare_enable(sensor->xclk);
23680f7acb52SHugues Fruchet 	if (ret) {
23690f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to enable clock\n",
23700f7acb52SHugues Fruchet 			__func__);
23710f7acb52SHugues Fruchet 		return ret;
23720f7acb52SHugues Fruchet 	}
237319a81c14SSteve Longerbeam 
237419a81c14SSteve Longerbeam 	ret = regulator_bulk_enable(OV5640_NUM_SUPPLIES,
237519a81c14SSteve Longerbeam 				    sensor->supplies);
23760f7acb52SHugues Fruchet 	if (ret) {
23770f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to enable regulators\n",
23780f7acb52SHugues Fruchet 			__func__);
237919a81c14SSteve Longerbeam 		goto xclk_off;
23800f7acb52SHugues Fruchet 	}
238119a81c14SSteve Longerbeam 
238219a81c14SSteve Longerbeam 	ov5640_reset(sensor);
238319a81c14SSteve Longerbeam 	ov5640_power(sensor, true);
238419a81c14SSteve Longerbeam 
238519a81c14SSteve Longerbeam 	ret = ov5640_init_slave_id(sensor);
238619a81c14SSteve Longerbeam 	if (ret)
238719a81c14SSteve Longerbeam 		goto power_off;
238819a81c14SSteve Longerbeam 
23890f7acb52SHugues Fruchet 	return 0;
23900f7acb52SHugues Fruchet 
23910f7acb52SHugues Fruchet power_off:
23920f7acb52SHugues Fruchet 	ov5640_power(sensor, false);
23930f7acb52SHugues Fruchet 	regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies);
23940f7acb52SHugues Fruchet xclk_off:
23950f7acb52SHugues Fruchet 	clk_disable_unprepare(sensor->xclk);
23960f7acb52SHugues Fruchet 	return ret;
23970f7acb52SHugues Fruchet }
23980f7acb52SHugues Fruchet 
23990f7acb52SHugues Fruchet static void ov5640_set_power_off(struct ov5640_dev *sensor)
24000f7acb52SHugues Fruchet {
24010f7acb52SHugues Fruchet 	ov5640_power(sensor, false);
24020f7acb52SHugues Fruchet 	regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies);
24030f7acb52SHugues Fruchet 	clk_disable_unprepare(sensor->xclk);
24040f7acb52SHugues Fruchet }
24050f7acb52SHugues Fruchet 
2406b1751ae6SLad Prabhakar static int ov5640_set_power_mipi(struct ov5640_dev *sensor, bool on)
2407b1751ae6SLad Prabhakar {
2408b1751ae6SLad Prabhakar 	int ret;
2409b1751ae6SLad Prabhakar 
2410b1751ae6SLad Prabhakar 	if (!on) {
2411b1751ae6SLad Prabhakar 		/* Reset MIPI bus settings to their default values. */
2412b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
2413b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x04);
2414b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x00);
2415b1751ae6SLad Prabhakar 		return 0;
2416b1751ae6SLad Prabhakar 	}
2417b1751ae6SLad Prabhakar 
2418b1751ae6SLad Prabhakar 	/*
2419b1751ae6SLad Prabhakar 	 * Power up MIPI HS Tx and LS Rx; 2 data lanes mode
2420b1751ae6SLad Prabhakar 	 *
2421b1751ae6SLad Prabhakar 	 * 0x300e = 0x40
2422b1751ae6SLad Prabhakar 	 * [7:5] = 010	: 2 data lanes mode (see FIXME note in
2423b1751ae6SLad Prabhakar 	 *		  "ov5640_set_stream_mipi()")
2424b1751ae6SLad Prabhakar 	 * [4] = 0	: Power up MIPI HS Tx
2425b1751ae6SLad Prabhakar 	 * [3] = 0	: Power up MIPI LS Rx
2426b1751ae6SLad Prabhakar 	 * [2] = 0	: MIPI interface disabled
2427b1751ae6SLad Prabhakar 	 */
2428b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x40);
2429b1751ae6SLad Prabhakar 	if (ret)
2430b1751ae6SLad Prabhakar 		return ret;
2431b1751ae6SLad Prabhakar 
2432b1751ae6SLad Prabhakar 	/*
2433b1751ae6SLad Prabhakar 	 * Gate clock and set LP11 in 'no packets mode' (idle)
2434b1751ae6SLad Prabhakar 	 *
2435b1751ae6SLad Prabhakar 	 * 0x4800 = 0x24
2436b1751ae6SLad Prabhakar 	 * [5] = 1	: Gate clock when 'no packets'
2437b1751ae6SLad Prabhakar 	 * [2] = 1	: MIPI bus in LP11 when 'no packets'
2438b1751ae6SLad Prabhakar 	 */
2439b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x24);
2440b1751ae6SLad Prabhakar 	if (ret)
2441b1751ae6SLad Prabhakar 		return ret;
2442b1751ae6SLad Prabhakar 
2443b1751ae6SLad Prabhakar 	/*
2444b1751ae6SLad Prabhakar 	 * Set data lanes and clock in LP11 when 'sleeping'
2445b1751ae6SLad Prabhakar 	 *
2446b1751ae6SLad Prabhakar 	 * 0x3019 = 0x70
2447b1751ae6SLad Prabhakar 	 * [6] = 1	: MIPI data lane 2 in LP11 when 'sleeping'
2448b1751ae6SLad Prabhakar 	 * [5] = 1	: MIPI data lane 1 in LP11 when 'sleeping'
2449b1751ae6SLad Prabhakar 	 * [4] = 1	: MIPI clock lane in LP11 when 'sleeping'
2450b1751ae6SLad Prabhakar 	 */
2451b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x70);
2452b1751ae6SLad Prabhakar 	if (ret)
2453b1751ae6SLad Prabhakar 		return ret;
2454b1751ae6SLad Prabhakar 
2455b1751ae6SLad Prabhakar 	/* Give lanes some time to coax into LP11 state. */
2456b1751ae6SLad Prabhakar 	usleep_range(500, 1000);
2457b1751ae6SLad Prabhakar 
2458b1751ae6SLad Prabhakar 	return 0;
2459b1751ae6SLad Prabhakar }
2460b1751ae6SLad Prabhakar 
2461576f5d4bSLad Prabhakar static int ov5640_set_power_dvp(struct ov5640_dev *sensor, bool on)
2462576f5d4bSLad Prabhakar {
2463311a6408SLad Prabhakar 	unsigned int flags = sensor->ep.bus.parallel.flags;
246468579b32SHugues Fruchet 	bool bt656 = sensor->ep.bus_type == V4L2_MBUS_BT656;
246568579b32SHugues Fruchet 	u8 polarities = 0;
2466576f5d4bSLad Prabhakar 	int ret;
2467576f5d4bSLad Prabhakar 
2468576f5d4bSLad Prabhakar 	if (!on) {
2469576f5d4bSLad Prabhakar 		/* Reset settings to their default values. */
247068579b32SHugues Fruchet 		ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00, 0x00);
2471311a6408SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
2472311a6408SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, 0x20);
2473576f5d4bSLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01, 0x00);
2474576f5d4bSLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0x00);
2475576f5d4bSLad Prabhakar 		return 0;
2476576f5d4bSLad Prabhakar 	}
2477576f5d4bSLad Prabhakar 
2478576f5d4bSLad Prabhakar 	/*
2479311a6408SLad Prabhakar 	 * Note about parallel port configuration.
2480311a6408SLad Prabhakar 	 *
2481311a6408SLad Prabhakar 	 * When configured in parallel mode, the OV5640 will
2482311a6408SLad Prabhakar 	 * output 10 bits data on DVP data lines [9:0].
2483311a6408SLad Prabhakar 	 * If only 8 bits data are wanted, the 8 bits data lines
2484311a6408SLad Prabhakar 	 * of the camera interface must be physically connected
2485311a6408SLad Prabhakar 	 * on the DVP data lines [9:2].
2486311a6408SLad Prabhakar 	 *
2487311a6408SLad Prabhakar 	 * Control lines polarity can be configured through
2488311a6408SLad Prabhakar 	 * devicetree endpoint control lines properties.
2489311a6408SLad Prabhakar 	 * If no endpoint control lines properties are set,
2490311a6408SLad Prabhakar 	 * polarity will be as below:
2491311a6408SLad Prabhakar 	 * - VSYNC:	active high
2492311a6408SLad Prabhakar 	 * - HREF:	active low
2493311a6408SLad Prabhakar 	 * - PCLK:	active low
249468579b32SHugues Fruchet 	 *
249568579b32SHugues Fruchet 	 * VSYNC & HREF are not configured if BT656 bus mode is selected
2496311a6408SLad Prabhakar 	 */
249768579b32SHugues Fruchet 
249868579b32SHugues Fruchet 	/*
249968579b32SHugues Fruchet 	 * BT656 embedded synchronization configuration
250068579b32SHugues Fruchet 	 *
250168579b32SHugues Fruchet 	 * CCIR656 CTRL00
250268579b32SHugues Fruchet 	 * - [7]:	SYNC code selection (0: auto generate sync code,
250368579b32SHugues Fruchet 	 *		1: sync code from regs 0x4732-0x4735)
250468579b32SHugues Fruchet 	 * - [6]:	f value in CCIR656 SYNC code when fixed f value
250568579b32SHugues Fruchet 	 * - [5]:	Fixed f value
250668579b32SHugues Fruchet 	 * - [4:3]:	Blank toggle data options (00: data=1'h040/1'h200,
250768579b32SHugues Fruchet 	 *		01: data from regs 0x4736-0x4738, 10: always keep 0)
250868579b32SHugues Fruchet 	 * - [1]:	Clip data disable
250968579b32SHugues Fruchet 	 * - [0]:	CCIR656 mode enable
251068579b32SHugues Fruchet 	 *
251168579b32SHugues Fruchet 	 * Default CCIR656 SAV/EAV mode with default codes
251268579b32SHugues Fruchet 	 * SAV=0xff000080 & EAV=0xff00009d is enabled here with settings:
251368579b32SHugues Fruchet 	 * - CCIR656 mode enable
251468579b32SHugues Fruchet 	 * - auto generation of sync codes
251568579b32SHugues Fruchet 	 * - blank toggle data 1'h040/1'h200
251668579b32SHugues Fruchet 	 * - clip reserved data (0x00 & 0xff changed to 0x01 & 0xfe)
251768579b32SHugues Fruchet 	 */
251868579b32SHugues Fruchet 	ret = ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00,
251968579b32SHugues Fruchet 			       bt656 ? 0x01 : 0x00);
252068579b32SHugues Fruchet 	if (ret)
252168579b32SHugues Fruchet 		return ret;
252268579b32SHugues Fruchet 
2523311a6408SLad Prabhakar 	/*
2524311a6408SLad Prabhakar 	 * configure parallel port control lines polarity
2525311a6408SLad Prabhakar 	 *
2526311a6408SLad Prabhakar 	 * POLARITY CTRL0
2527311a6408SLad Prabhakar 	 * - [5]:	PCLK polarity (0: active low, 1: active high)
2528311a6408SLad Prabhakar 	 * - [1]:	HREF polarity (0: active low, 1: active high)
2529311a6408SLad Prabhakar 	 * - [0]:	VSYNC polarity (mismatch here between
2530311a6408SLad Prabhakar 	 *		datasheet and hardware, 0 is active high
2531311a6408SLad Prabhakar 	 *		and 1 is active low...)
2532311a6408SLad Prabhakar 	 */
253368579b32SHugues Fruchet 	if (!bt656) {
2534311a6408SLad Prabhakar 		if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
253568579b32SHugues Fruchet 			polarities |= BIT(1);
2536311a6408SLad Prabhakar 		if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
253768579b32SHugues Fruchet 			polarities |= BIT(0);
253868579b32SHugues Fruchet 	}
253968579b32SHugues Fruchet 	if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
254068579b32SHugues Fruchet 		polarities |= BIT(5);
2541311a6408SLad Prabhakar 
254268579b32SHugues Fruchet 	ret = ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, polarities);
2543311a6408SLad Prabhakar 	if (ret)
2544311a6408SLad Prabhakar 		return ret;
2545311a6408SLad Prabhakar 
2546311a6408SLad Prabhakar 	/*
254768579b32SHugues Fruchet 	 * powerdown MIPI TX/RX PHY & enable DVP
2548311a6408SLad Prabhakar 	 *
2549311a6408SLad Prabhakar 	 * MIPI CONTROL 00
255068579b32SHugues Fruchet 	 * [4] = 1	: Power down MIPI HS Tx
255168579b32SHugues Fruchet 	 * [3] = 1	: Power down MIPI LS Rx
255268579b32SHugues Fruchet 	 * [2] = 0	: DVP enable (MIPI disable)
2553311a6408SLad Prabhakar 	 */
2554311a6408SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x18);
2555311a6408SLad Prabhakar 	if (ret)
2556311a6408SLad Prabhakar 		return ret;
2557311a6408SLad Prabhakar 
2558311a6408SLad Prabhakar 	/*
2559576f5d4bSLad Prabhakar 	 * enable VSYNC/HREF/PCLK DVP control lines
2560576f5d4bSLad Prabhakar 	 * & D[9:6] DVP data lines
2561576f5d4bSLad Prabhakar 	 *
2562576f5d4bSLad Prabhakar 	 * PAD OUTPUT ENABLE 01
2563576f5d4bSLad Prabhakar 	 * - 6:		VSYNC output enable
2564576f5d4bSLad Prabhakar 	 * - 5:		HREF output enable
2565576f5d4bSLad Prabhakar 	 * - 4:		PCLK output enable
2566576f5d4bSLad Prabhakar 	 * - [3:0]:	D[9:6] output enable
2567576f5d4bSLad Prabhakar 	 */
25684039b037SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01,
256968579b32SHugues Fruchet 			       bt656 ? 0x1f : 0x7f);
2570576f5d4bSLad Prabhakar 	if (ret)
2571576f5d4bSLad Prabhakar 		return ret;
2572576f5d4bSLad Prabhakar 
2573576f5d4bSLad Prabhakar 	/*
2574576f5d4bSLad Prabhakar 	 * enable D[5:0] DVP data lines
2575576f5d4bSLad Prabhakar 	 *
2576576f5d4bSLad Prabhakar 	 * PAD OUTPUT ENABLE 02
2577576f5d4bSLad Prabhakar 	 * - [7:2]:	D[5:0] output enable
2578576f5d4bSLad Prabhakar 	 */
2579576f5d4bSLad Prabhakar 	return ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0xfc);
2580576f5d4bSLad Prabhakar }
2581576f5d4bSLad Prabhakar 
25820f7acb52SHugues Fruchet static int ov5640_set_power(struct ov5640_dev *sensor, bool on)
25830f7acb52SHugues Fruchet {
25840f7acb52SHugues Fruchet 	int ret = 0;
25850f7acb52SHugues Fruchet 
25860f7acb52SHugues Fruchet 	if (on) {
25870f7acb52SHugues Fruchet 		ret = ov5640_set_power_on(sensor);
25880f7acb52SHugues Fruchet 		if (ret)
25890f7acb52SHugues Fruchet 			return ret;
25900f7acb52SHugues Fruchet 
259119a81c14SSteve Longerbeam 		ret = ov5640_restore_mode(sensor);
259219a81c14SSteve Longerbeam 		if (ret)
259319a81c14SSteve Longerbeam 			goto power_off;
2594b1751ae6SLad Prabhakar 	}
259519a81c14SSteve Longerbeam 
2596576f5d4bSLad Prabhakar 	if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY)
2597b1751ae6SLad Prabhakar 		ret = ov5640_set_power_mipi(sensor, on);
2598576f5d4bSLad Prabhakar 	else
2599576f5d4bSLad Prabhakar 		ret = ov5640_set_power_dvp(sensor, on);
2600b1751ae6SLad Prabhakar 	if (ret)
2601b1751ae6SLad Prabhakar 		goto power_off;
2602aa4bb8b8SJacopo Mondi 
2603b1751ae6SLad Prabhakar 	if (!on)
2604aa4bb8b8SJacopo Mondi 		ov5640_set_power_off(sensor);
260519a81c14SSteve Longerbeam 
260619a81c14SSteve Longerbeam 	return 0;
260719a81c14SSteve Longerbeam 
260819a81c14SSteve Longerbeam power_off:
26090f7acb52SHugues Fruchet 	ov5640_set_power_off(sensor);
261019a81c14SSteve Longerbeam 	return ret;
261119a81c14SSteve Longerbeam }
261219a81c14SSteve Longerbeam 
261319a81c14SSteve Longerbeam /* --------------- Subdev Operations --------------- */
261419a81c14SSteve Longerbeam 
261519a81c14SSteve Longerbeam static int ov5640_s_power(struct v4l2_subdev *sd, int on)
261619a81c14SSteve Longerbeam {
261719a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
261819a81c14SSteve Longerbeam 	int ret = 0;
261919a81c14SSteve Longerbeam 
262019a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
262119a81c14SSteve Longerbeam 
262219a81c14SSteve Longerbeam 	/*
262319a81c14SSteve Longerbeam 	 * If the power count is modified from 0 to != 0 or from != 0 to 0,
262419a81c14SSteve Longerbeam 	 * update the power state.
262519a81c14SSteve Longerbeam 	 */
262619a81c14SSteve Longerbeam 	if (sensor->power_count == !on) {
262719a81c14SSteve Longerbeam 		ret = ov5640_set_power(sensor, !!on);
262819a81c14SSteve Longerbeam 		if (ret)
262919a81c14SSteve Longerbeam 			goto out;
263019a81c14SSteve Longerbeam 	}
263119a81c14SSteve Longerbeam 
263219a81c14SSteve Longerbeam 	/* Update the power count. */
263319a81c14SSteve Longerbeam 	sensor->power_count += on ? 1 : -1;
263419a81c14SSteve Longerbeam 	WARN_ON(sensor->power_count < 0);
263519a81c14SSteve Longerbeam out:
263619a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
263719a81c14SSteve Longerbeam 
263819a81c14SSteve Longerbeam 	if (on && !ret && sensor->power_count == 1) {
263919a81c14SSteve Longerbeam 		/* restore controls */
264019a81c14SSteve Longerbeam 		ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
264119a81c14SSteve Longerbeam 	}
264219a81c14SSteve Longerbeam 
264319a81c14SSteve Longerbeam 	return ret;
264419a81c14SSteve Longerbeam }
264519a81c14SSteve Longerbeam 
264619a81c14SSteve Longerbeam static int ov5640_try_frame_interval(struct ov5640_dev *sensor,
264719a81c14SSteve Longerbeam 				     struct v4l2_fract *fi,
264819a81c14SSteve Longerbeam 				     u32 width, u32 height)
264919a81c14SSteve Longerbeam {
265019a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
26516530a5ebSJagan Teki 	enum ov5640_frame_rate rate = OV5640_15_FPS;
2652f6cc192fSMaxime Ripard 	int minfps, maxfps, best_fps, fps;
2653f6cc192fSMaxime Ripard 	int i;
265419a81c14SSteve Longerbeam 
265519a81c14SSteve Longerbeam 	minfps = ov5640_framerates[OV5640_15_FPS];
2656e823fb16SMaxime Ripard 	maxfps = ov5640_framerates[OV5640_60_FPS];
265719a81c14SSteve Longerbeam 
265819a81c14SSteve Longerbeam 	if (fi->numerator == 0) {
265919a81c14SSteve Longerbeam 		fi->denominator = maxfps;
266019a81c14SSteve Longerbeam 		fi->numerator = 1;
2661e823fb16SMaxime Ripard 		rate = OV5640_60_FPS;
2662e823fb16SMaxime Ripard 		goto find_mode;
266319a81c14SSteve Longerbeam 	}
266419a81c14SSteve Longerbeam 
2665f6cc192fSMaxime Ripard 	fps = clamp_val(DIV_ROUND_CLOSEST(fi->denominator, fi->numerator),
2666f6cc192fSMaxime Ripard 			minfps, maxfps);
2667f6cc192fSMaxime Ripard 
2668f6cc192fSMaxime Ripard 	best_fps = minfps;
2669f6cc192fSMaxime Ripard 	for (i = 0; i < ARRAY_SIZE(ov5640_framerates); i++) {
2670f6cc192fSMaxime Ripard 		int curr_fps = ov5640_framerates[i];
2671f6cc192fSMaxime Ripard 
2672f6cc192fSMaxime Ripard 		if (abs(curr_fps - fps) < abs(best_fps - fps)) {
2673f6cc192fSMaxime Ripard 			best_fps = curr_fps;
2674f6cc192fSMaxime Ripard 			rate = i;
2675f6cc192fSMaxime Ripard 		}
2676f6cc192fSMaxime Ripard 	}
267719a81c14SSteve Longerbeam 
267819a81c14SSteve Longerbeam 	fi->numerator = 1;
2679f6cc192fSMaxime Ripard 	fi->denominator = best_fps;
268019a81c14SSteve Longerbeam 
2681e823fb16SMaxime Ripard find_mode:
26825a3ad937SMaxime Ripard 	mode = ov5640_find_mode(sensor, rate, width, height, false);
26835a3ad937SMaxime Ripard 	return mode ? rate : -EINVAL;
268419a81c14SSteve Longerbeam }
268519a81c14SSteve Longerbeam 
268619a81c14SSteve Longerbeam static int ov5640_get_fmt(struct v4l2_subdev *sd,
26870d346d2aSTomi Valkeinen 			  struct v4l2_subdev_state *sd_state,
268819a81c14SSteve Longerbeam 			  struct v4l2_subdev_format *format)
268919a81c14SSteve Longerbeam {
269019a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
269119a81c14SSteve Longerbeam 	struct v4l2_mbus_framefmt *fmt;
269219a81c14SSteve Longerbeam 
269319a81c14SSteve Longerbeam 	if (format->pad != 0)
269419a81c14SSteve Longerbeam 		return -EINVAL;
269519a81c14SSteve Longerbeam 
269619a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
269719a81c14SSteve Longerbeam 
269819a81c14SSteve Longerbeam 	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
26990d346d2aSTomi Valkeinen 		fmt = v4l2_subdev_get_try_format(&sensor->sd, sd_state,
270019a81c14SSteve Longerbeam 						 format->pad);
270119a81c14SSteve Longerbeam 	else
270219a81c14SSteve Longerbeam 		fmt = &sensor->fmt;
270319a81c14SSteve Longerbeam 
270419a81c14SSteve Longerbeam 	format->format = *fmt;
270519a81c14SSteve Longerbeam 
270619a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
270719a81c14SSteve Longerbeam 
270819a81c14SSteve Longerbeam 	return 0;
270919a81c14SSteve Longerbeam }
271019a81c14SSteve Longerbeam 
271119a81c14SSteve Longerbeam static int ov5640_try_fmt_internal(struct v4l2_subdev *sd,
271219a81c14SSteve Longerbeam 				   struct v4l2_mbus_framefmt *fmt,
271319a81c14SSteve Longerbeam 				   enum ov5640_frame_rate fr,
271419a81c14SSteve Longerbeam 				   const struct ov5640_mode_info **new_mode)
271519a81c14SSteve Longerbeam {
271619a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
271719a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
2718e3ee691dSHugues Fruchet 	int i;
271919a81c14SSteve Longerbeam 
272019a81c14SSteve Longerbeam 	mode = ov5640_find_mode(sensor, fr, fmt->width, fmt->height, true);
272119a81c14SSteve Longerbeam 	if (!mode)
272219a81c14SSteve Longerbeam 		return -EINVAL;
27235113d5b3SJacopo Mondi 	fmt->width = mode->width;
27245113d5b3SJacopo Mondi 	fmt->height = mode->height;
272519a81c14SSteve Longerbeam 
272619a81c14SSteve Longerbeam 	if (new_mode)
272719a81c14SSteve Longerbeam 		*new_mode = mode;
2728e3ee691dSHugues Fruchet 
2729e3ee691dSHugues Fruchet 	for (i = 0; i < ARRAY_SIZE(ov5640_formats); i++)
2730e3ee691dSHugues Fruchet 		if (ov5640_formats[i].code == fmt->code)
2731e3ee691dSHugues Fruchet 			break;
2732e3ee691dSHugues Fruchet 	if (i >= ARRAY_SIZE(ov5640_formats))
2733e6441fdeSHugues Fruchet 		i = 0;
2734e6441fdeSHugues Fruchet 
2735e6441fdeSHugues Fruchet 	fmt->code = ov5640_formats[i].code;
2736e6441fdeSHugues Fruchet 	fmt->colorspace = ov5640_formats[i].colorspace;
2737e6441fdeSHugues Fruchet 	fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
2738e6441fdeSHugues Fruchet 	fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
2739e6441fdeSHugues Fruchet 	fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
2740e3ee691dSHugues Fruchet 
274119a81c14SSteve Longerbeam 	return 0;
274219a81c14SSteve Longerbeam }
274319a81c14SSteve Longerbeam 
27443c28588fSJacopo Mondi static int ov5640_update_pixel_rate(struct ov5640_dev *sensor)
27453c28588fSJacopo Mondi {
27463c28588fSJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
27473c28588fSJacopo Mondi 	enum ov5640_pixel_rate_id pixel_rate_id = mode->pixel_rate;
27483c28588fSJacopo Mondi 	struct v4l2_mbus_framefmt *fmt = &sensor->fmt;
27493c28588fSJacopo Mondi 	unsigned int i = 0;
27503c28588fSJacopo Mondi 	u32 pixel_rate;
27513c28588fSJacopo Mondi 	s64 link_freq;
27523c28588fSJacopo Mondi 	u32 num_lanes;
27533c28588fSJacopo Mondi 	u32 bpp;
27543c28588fSJacopo Mondi 
27553c28588fSJacopo Mondi 	/*
27563c28588fSJacopo Mondi 	 * Update the pixel rate control value.
27573c28588fSJacopo Mondi 	 *
27583c28588fSJacopo Mondi 	 * For DVP mode, maintain the pixel rate calculation using fixed FPS.
27593c28588fSJacopo Mondi 	 */
27603c28588fSJacopo Mondi 	if (!ov5640_is_csi2(sensor)) {
27613c28588fSJacopo Mondi 		__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate,
27623c28588fSJacopo Mondi 					 ov5640_calc_pixel_rate(sensor));
27633c28588fSJacopo Mondi 
27643c28588fSJacopo Mondi 		return 0;
27653c28588fSJacopo Mondi 	}
27663c28588fSJacopo Mondi 
27673c28588fSJacopo Mondi 	/*
27683c28588fSJacopo Mondi 	 * The MIPI CSI-2 link frequency should comply with the CSI-2
27693c28588fSJacopo Mondi 	 * specification and be lower than 1GHz.
27703c28588fSJacopo Mondi 	 *
27713c28588fSJacopo Mondi 	 * Start from the suggested pixel_rate for the current mode and
27723c28588fSJacopo Mondi 	 * progressively slow it down if it exceeds 1GHz.
27733c28588fSJacopo Mondi 	 */
27743c28588fSJacopo Mondi 	num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes;
27753c28588fSJacopo Mondi 	bpp = ov5640_code_to_bpp(fmt->code);
27763c28588fSJacopo Mondi 	do {
27773c28588fSJacopo Mondi 		pixel_rate = ov5640_pixel_rates[pixel_rate_id];
27783c28588fSJacopo Mondi 		link_freq = pixel_rate * bpp / (2 * num_lanes);
27793c28588fSJacopo Mondi 	} while (link_freq >= 1000000000U &&
27803c28588fSJacopo Mondi 		 ++pixel_rate_id < OV5640_NUM_PIXEL_RATES);
27813c28588fSJacopo Mondi 
27823c28588fSJacopo Mondi 	sensor->current_link_freq = link_freq;
27833c28588fSJacopo Mondi 
27843c28588fSJacopo Mondi 	/*
27853c28588fSJacopo Mondi 	 * Higher link rates require the clock tree to be programmed with
27863c28588fSJacopo Mondi 	 * 'mipi_div' = 1; this has the effect of halving the actual output
27873c28588fSJacopo Mondi 	 * pixel rate in the MIPI domain.
27883c28588fSJacopo Mondi 	 *
27893c28588fSJacopo Mondi 	 * Adjust the pixel rate and link frequency control value to report it
27903c28588fSJacopo Mondi 	 * correctly to userspace.
27913c28588fSJacopo Mondi 	 */
27923c28588fSJacopo Mondi 	if (link_freq > OV5640_LINK_RATE_MAX) {
27933c28588fSJacopo Mondi 		pixel_rate /= 2;
27943c28588fSJacopo Mondi 		link_freq /= 2;
27953c28588fSJacopo Mondi 	}
27963c28588fSJacopo Mondi 
27973c28588fSJacopo Mondi 	for (i = 0; i < ARRAY_SIZE(ov5640_csi2_link_freqs); ++i) {
27983c28588fSJacopo Mondi 		if (ov5640_csi2_link_freqs[i] == link_freq)
27993c28588fSJacopo Mondi 			break;
28003c28588fSJacopo Mondi 	}
28013c28588fSJacopo Mondi 	WARN_ON(i == ARRAY_SIZE(ov5640_csi2_link_freqs));
28023c28588fSJacopo Mondi 
28033c28588fSJacopo Mondi 	__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, pixel_rate);
28043c28588fSJacopo Mondi 	__v4l2_ctrl_s_ctrl(sensor->ctrls.link_freq, i);
28053c28588fSJacopo Mondi 
28063c28588fSJacopo Mondi 	return 0;
28073c28588fSJacopo Mondi }
28083c28588fSJacopo Mondi 
280919a81c14SSteve Longerbeam static int ov5640_set_fmt(struct v4l2_subdev *sd,
28100d346d2aSTomi Valkeinen 			  struct v4l2_subdev_state *sd_state,
281119a81c14SSteve Longerbeam 			  struct v4l2_subdev_format *format)
281219a81c14SSteve Longerbeam {
281319a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
281419a81c14SSteve Longerbeam 	const struct ov5640_mode_info *new_mode;
2815e6441fdeSHugues Fruchet 	struct v4l2_mbus_framefmt *mbus_fmt = &format->format;
281619a81c14SSteve Longerbeam 	int ret;
281719a81c14SSteve Longerbeam 
281819a81c14SSteve Longerbeam 	if (format->pad != 0)
281919a81c14SSteve Longerbeam 		return -EINVAL;
282019a81c14SSteve Longerbeam 
282119a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
282219a81c14SSteve Longerbeam 
282319a81c14SSteve Longerbeam 	if (sensor->streaming) {
282419a81c14SSteve Longerbeam 		ret = -EBUSY;
282519a81c14SSteve Longerbeam 		goto out;
282619a81c14SSteve Longerbeam 	}
282719a81c14SSteve Longerbeam 
2828e6441fdeSHugues Fruchet 	ret = ov5640_try_fmt_internal(sd, mbus_fmt,
282919a81c14SSteve Longerbeam 				      sensor->current_fr, &new_mode);
283019a81c14SSteve Longerbeam 	if (ret)
283119a81c14SSteve Longerbeam 		goto out;
283219a81c14SSteve Longerbeam 
2833e738f5ddSMirela Rabulea 	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
2834e738f5ddSMirela Rabulea 		*v4l2_subdev_get_try_format(sd, sd_state, 0) = *mbus_fmt;
2835e738f5ddSMirela Rabulea 		goto out;
2836e738f5ddSMirela Rabulea 	}
283719a81c14SSteve Longerbeam 
28386949d864SHugues Fruchet 	if (new_mode != sensor->current_mode) {
283919a81c14SSteve Longerbeam 		sensor->current_mode = new_mode;
284019a81c14SSteve Longerbeam 		sensor->pending_mode_change = true;
28416949d864SHugues Fruchet 	}
284207115449SJacopo Mondi 	if (mbus_fmt->code != sensor->fmt.code)
2843fb98e29fSHugues Fruchet 		sensor->pending_fmt_change = true;
284407115449SJacopo Mondi 
2845e738f5ddSMirela Rabulea 	/* update format even if code is unchanged, resolution might change */
2846e738f5ddSMirela Rabulea 	sensor->fmt = *mbus_fmt;
2847e738f5ddSMirela Rabulea 
28483c28588fSJacopo Mondi 	ov5640_update_pixel_rate(sensor);
28493c28588fSJacopo Mondi 
285019a81c14SSteve Longerbeam out:
285119a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
285219a81c14SSteve Longerbeam 	return ret;
285319a81c14SSteve Longerbeam }
285419a81c14SSteve Longerbeam 
2855e3ee691dSHugues Fruchet static int ov5640_set_framefmt(struct ov5640_dev *sensor,
2856e3ee691dSHugues Fruchet 			       struct v4l2_mbus_framefmt *format)
2857e3ee691dSHugues Fruchet {
2858e3ee691dSHugues Fruchet 	int ret = 0;
2859d47c4126SHugues Fruchet 	bool is_jpeg = false;
2860b7ed3abdSLoic Poulain 	u8 fmt, mux;
2861e3ee691dSHugues Fruchet 
2862e3ee691dSHugues Fruchet 	switch (format->code) {
28631536fbdbSXavier Roumegue 	case MEDIA_BUS_FMT_UYVY8_1X16:
2864e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_UYVY8_2X8:
2865e3ee691dSHugues Fruchet 		/* YUV422, UYVY */
2866b7ed3abdSLoic Poulain 		fmt = 0x3f;
2867b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_YUV422;
2868e3ee691dSHugues Fruchet 		break;
28691536fbdbSXavier Roumegue 	case MEDIA_BUS_FMT_YUYV8_1X16:
2870e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_YUYV8_2X8:
2871e3ee691dSHugues Fruchet 		/* YUV422, YUYV */
2872b7ed3abdSLoic Poulain 		fmt = 0x30;
2873b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_YUV422;
2874e3ee691dSHugues Fruchet 		break;
2875e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_RGB565_2X8_LE:
2876e3ee691dSHugues Fruchet 		/* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */
2877b7ed3abdSLoic Poulain 		fmt = 0x6F;
2878b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RGB;
2879e3ee691dSHugues Fruchet 		break;
2880e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_RGB565_2X8_BE:
2881e3ee691dSHugues Fruchet 		/* RGB565 {r[4:0],g[5:3]},{g[2:0],b[4:0]} */
2882b7ed3abdSLoic Poulain 		fmt = 0x61;
2883b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RGB;
2884e3ee691dSHugues Fruchet 		break;
2885d47c4126SHugues Fruchet 	case MEDIA_BUS_FMT_JPEG_1X8:
2886d47c4126SHugues Fruchet 		/* YUV422, YUYV */
2887b7ed3abdSLoic Poulain 		fmt = 0x30;
2888b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_YUV422;
2889d47c4126SHugues Fruchet 		is_jpeg = true;
2890d47c4126SHugues Fruchet 		break;
2891b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SBGGR8_1X8:
2892b7ed3abdSLoic Poulain 		/* Raw, BGBG... / GRGR... */
2893b7ed3abdSLoic Poulain 		fmt = 0x00;
2894b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2895b7ed3abdSLoic Poulain 		break;
2896b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SGBRG8_1X8:
2897b7ed3abdSLoic Poulain 		/* Raw bayer, GBGB... / RGRG... */
2898b7ed3abdSLoic Poulain 		fmt = 0x01;
2899b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2900b7ed3abdSLoic Poulain 		break;
2901b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SGRBG8_1X8:
2902b7ed3abdSLoic Poulain 		/* Raw bayer, GRGR... / BGBG... */
2903b7ed3abdSLoic Poulain 		fmt = 0x02;
2904b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2905b7ed3abdSLoic Poulain 		break;
2906b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SRGGB8_1X8:
2907b7ed3abdSLoic Poulain 		/* Raw bayer, RGRG... / GBGB... */
2908b7ed3abdSLoic Poulain 		fmt = 0x03;
2909b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2910b7ed3abdSLoic Poulain 		break;
2911e3ee691dSHugues Fruchet 	default:
2912e3ee691dSHugues Fruchet 		return -EINVAL;
2913e3ee691dSHugues Fruchet 	}
2914e3ee691dSHugues Fruchet 
2915e3ee691dSHugues Fruchet 	/* FORMAT CONTROL00: YUV and RGB formatting */
2916b7ed3abdSLoic Poulain 	ret = ov5640_write_reg(sensor, OV5640_REG_FORMAT_CONTROL00, fmt);
2917e3ee691dSHugues Fruchet 	if (ret)
2918e3ee691dSHugues Fruchet 		return ret;
2919e3ee691dSHugues Fruchet 
2920e3ee691dSHugues Fruchet 	/* FORMAT MUX CONTROL: ISP YUV or RGB */
2921b7ed3abdSLoic Poulain 	ret = ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL, mux);
2922d47c4126SHugues Fruchet 	if (ret)
2923d47c4126SHugues Fruchet 		return ret;
2924d47c4126SHugues Fruchet 
2925d47c4126SHugues Fruchet 	/*
2926d47c4126SHugues Fruchet 	 * TIMING TC REG21:
2927d47c4126SHugues Fruchet 	 * - [5]:	JPEG enable
2928d47c4126SHugues Fruchet 	 */
2929d47c4126SHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
2930d47c4126SHugues Fruchet 			     BIT(5), is_jpeg ? BIT(5) : 0);
2931d47c4126SHugues Fruchet 	if (ret)
2932d47c4126SHugues Fruchet 		return ret;
2933d47c4126SHugues Fruchet 
2934d47c4126SHugues Fruchet 	/*
2935d47c4126SHugues Fruchet 	 * SYSTEM RESET02:
2936d47c4126SHugues Fruchet 	 * - [4]:	Reset JFIFO
2937d47c4126SHugues Fruchet 	 * - [3]:	Reset SFIFO
2938d47c4126SHugues Fruchet 	 * - [2]:	Reset JPEG
2939d47c4126SHugues Fruchet 	 */
2940d47c4126SHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_RESET02,
2941d47c4126SHugues Fruchet 			     BIT(4) | BIT(3) | BIT(2),
2942d47c4126SHugues Fruchet 			     is_jpeg ? 0 : (BIT(4) | BIT(3) | BIT(2)));
2943d47c4126SHugues Fruchet 	if (ret)
2944d47c4126SHugues Fruchet 		return ret;
2945d47c4126SHugues Fruchet 
2946d47c4126SHugues Fruchet 	/*
2947d47c4126SHugues Fruchet 	 * CLOCK ENABLE02:
2948d47c4126SHugues Fruchet 	 * - [5]:	Enable JPEG 2x clock
2949d47c4126SHugues Fruchet 	 * - [3]:	Enable JPEG clock
2950d47c4126SHugues Fruchet 	 */
2951d47c4126SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_SYS_CLOCK_ENABLE02,
2952d47c4126SHugues Fruchet 			      BIT(5) | BIT(3),
2953d47c4126SHugues Fruchet 			      is_jpeg ? (BIT(5) | BIT(3)) : 0);
2954e3ee691dSHugues Fruchet }
295519a81c14SSteve Longerbeam 
295619a81c14SSteve Longerbeam /*
295719a81c14SSteve Longerbeam  * Sensor Controls.
295819a81c14SSteve Longerbeam  */
295919a81c14SSteve Longerbeam 
296019a81c14SSteve Longerbeam static int ov5640_set_ctrl_hue(struct ov5640_dev *sensor, int value)
296119a81c14SSteve Longerbeam {
296219a81c14SSteve Longerbeam 	int ret;
296319a81c14SSteve Longerbeam 
296419a81c14SSteve Longerbeam 	if (value) {
296519a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
296619a81c14SSteve Longerbeam 				     BIT(0), BIT(0));
296719a81c14SSteve Longerbeam 		if (ret)
296819a81c14SSteve Longerbeam 			return ret;
296919a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_SDE_CTRL1, value);
297019a81c14SSteve Longerbeam 	} else {
297119a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(0), 0);
297219a81c14SSteve Longerbeam 	}
297319a81c14SSteve Longerbeam 
297419a81c14SSteve Longerbeam 	return ret;
297519a81c14SSteve Longerbeam }
297619a81c14SSteve Longerbeam 
297719a81c14SSteve Longerbeam static int ov5640_set_ctrl_contrast(struct ov5640_dev *sensor, int value)
297819a81c14SSteve Longerbeam {
297919a81c14SSteve Longerbeam 	int ret;
298019a81c14SSteve Longerbeam 
298119a81c14SSteve Longerbeam 	if (value) {
298219a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
298319a81c14SSteve Longerbeam 				     BIT(2), BIT(2));
298419a81c14SSteve Longerbeam 		if (ret)
298519a81c14SSteve Longerbeam 			return ret;
298619a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL5,
298719a81c14SSteve Longerbeam 				       value & 0xff);
298819a81c14SSteve Longerbeam 	} else {
298919a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(2), 0);
299019a81c14SSteve Longerbeam 	}
299119a81c14SSteve Longerbeam 
299219a81c14SSteve Longerbeam 	return ret;
299319a81c14SSteve Longerbeam }
299419a81c14SSteve Longerbeam 
299519a81c14SSteve Longerbeam static int ov5640_set_ctrl_saturation(struct ov5640_dev *sensor, int value)
299619a81c14SSteve Longerbeam {
299719a81c14SSteve Longerbeam 	int ret;
299819a81c14SSteve Longerbeam 
299919a81c14SSteve Longerbeam 	if (value) {
300019a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
300119a81c14SSteve Longerbeam 				     BIT(1), BIT(1));
300219a81c14SSteve Longerbeam 		if (ret)
300319a81c14SSteve Longerbeam 			return ret;
300419a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL3,
300519a81c14SSteve Longerbeam 				       value & 0xff);
300619a81c14SSteve Longerbeam 		if (ret)
300719a81c14SSteve Longerbeam 			return ret;
300819a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL4,
300919a81c14SSteve Longerbeam 				       value & 0xff);
301019a81c14SSteve Longerbeam 	} else {
301119a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(1), 0);
301219a81c14SSteve Longerbeam 	}
301319a81c14SSteve Longerbeam 
301419a81c14SSteve Longerbeam 	return ret;
301519a81c14SSteve Longerbeam }
301619a81c14SSteve Longerbeam 
301719a81c14SSteve Longerbeam static int ov5640_set_ctrl_white_balance(struct ov5640_dev *sensor, int awb)
301819a81c14SSteve Longerbeam {
301919a81c14SSteve Longerbeam 	int ret;
302019a81c14SSteve Longerbeam 
302119a81c14SSteve Longerbeam 	ret = ov5640_mod_reg(sensor, OV5640_REG_AWB_MANUAL_CTRL,
302219a81c14SSteve Longerbeam 			     BIT(0), awb ? 0 : 1);
302319a81c14SSteve Longerbeam 	if (ret)
302419a81c14SSteve Longerbeam 		return ret;
302519a81c14SSteve Longerbeam 
302619a81c14SSteve Longerbeam 	if (!awb) {
302719a81c14SSteve Longerbeam 		u16 red = (u16)sensor->ctrls.red_balance->val;
302819a81c14SSteve Longerbeam 		u16 blue = (u16)sensor->ctrls.blue_balance->val;
302919a81c14SSteve Longerbeam 
303019a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_R_GAIN, red);
303119a81c14SSteve Longerbeam 		if (ret)
303219a81c14SSteve Longerbeam 			return ret;
303319a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_B_GAIN, blue);
303419a81c14SSteve Longerbeam 	}
303519a81c14SSteve Longerbeam 
303619a81c14SSteve Longerbeam 	return ret;
303719a81c14SSteve Longerbeam }
303819a81c14SSteve Longerbeam 
30393cca8ef5SHugues Fruchet static int ov5640_set_ctrl_exposure(struct ov5640_dev *sensor,
30403cca8ef5SHugues Fruchet 				    enum v4l2_exposure_auto_type auto_exposure)
304119a81c14SSteve Longerbeam {
304219a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
30433cca8ef5SHugues Fruchet 	bool auto_exp = (auto_exposure == V4L2_EXPOSURE_AUTO);
304419a81c14SSteve Longerbeam 	int ret = 0;
304519a81c14SSteve Longerbeam 
304619a81c14SSteve Longerbeam 	if (ctrls->auto_exp->is_new) {
30473cca8ef5SHugues Fruchet 		ret = ov5640_set_autoexposure(sensor, auto_exp);
304819a81c14SSteve Longerbeam 		if (ret)
304919a81c14SSteve Longerbeam 			return ret;
305019a81c14SSteve Longerbeam 	}
305119a81c14SSteve Longerbeam 
30523cca8ef5SHugues Fruchet 	if (!auto_exp && ctrls->exposure->is_new) {
305319a81c14SSteve Longerbeam 		u16 max_exp;
305419a81c14SSteve Longerbeam 
305519a81c14SSteve Longerbeam 		ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_VTS,
305619a81c14SSteve Longerbeam 					&max_exp);
305719a81c14SSteve Longerbeam 		if (ret)
305819a81c14SSteve Longerbeam 			return ret;
305919a81c14SSteve Longerbeam 		ret = ov5640_get_vts(sensor);
306019a81c14SSteve Longerbeam 		if (ret < 0)
306119a81c14SSteve Longerbeam 			return ret;
306219a81c14SSteve Longerbeam 		max_exp += ret;
30636146fde3SHugues Fruchet 		ret = 0;
306419a81c14SSteve Longerbeam 
306519a81c14SSteve Longerbeam 		if (ctrls->exposure->val < max_exp)
306619a81c14SSteve Longerbeam 			ret = ov5640_set_exposure(sensor, ctrls->exposure->val);
306719a81c14SSteve Longerbeam 	}
306819a81c14SSteve Longerbeam 
306919a81c14SSteve Longerbeam 	return ret;
307019a81c14SSteve Longerbeam }
307119a81c14SSteve Longerbeam 
30723cca8ef5SHugues Fruchet static int ov5640_set_ctrl_gain(struct ov5640_dev *sensor, bool auto_gain)
307319a81c14SSteve Longerbeam {
307419a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
307519a81c14SSteve Longerbeam 	int ret = 0;
307619a81c14SSteve Longerbeam 
307719a81c14SSteve Longerbeam 	if (ctrls->auto_gain->is_new) {
30783cca8ef5SHugues Fruchet 		ret = ov5640_set_autogain(sensor, auto_gain);
307919a81c14SSteve Longerbeam 		if (ret)
308019a81c14SSteve Longerbeam 			return ret;
308119a81c14SSteve Longerbeam 	}
308219a81c14SSteve Longerbeam 
30833cca8ef5SHugues Fruchet 	if (!auto_gain && ctrls->gain->is_new)
30843cca8ef5SHugues Fruchet 		ret = ov5640_set_gain(sensor, ctrls->gain->val);
308519a81c14SSteve Longerbeam 
308619a81c14SSteve Longerbeam 	return ret;
308719a81c14SSteve Longerbeam }
308819a81c14SSteve Longerbeam 
30899f6d7bacSChen-Yu Tsai static const char * const test_pattern_menu[] = {
30909f6d7bacSChen-Yu Tsai 	"Disabled",
30919f6d7bacSChen-Yu Tsai 	"Color bars",
3092bddc5cdfSChen-Yu Tsai 	"Color bars w/ rolling bar",
3093bddc5cdfSChen-Yu Tsai 	"Color squares",
3094bddc5cdfSChen-Yu Tsai 	"Color squares w/ rolling bar",
30959f6d7bacSChen-Yu Tsai };
30969f6d7bacSChen-Yu Tsai 
3097a0c29afbSChen-Yu Tsai #define OV5640_TEST_ENABLE		BIT(7)
3098a0c29afbSChen-Yu Tsai #define OV5640_TEST_ROLLING		BIT(6)	/* rolling horizontal bar */
3099a0c29afbSChen-Yu Tsai #define OV5640_TEST_TRANSPARENT		BIT(5)
3100a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE_BW		BIT(4)	/* black & white squares */
3101a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_STANDARD	(0 << 2)
3102a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_1	(1 << 2)
3103a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_HOR_CHANGE	(2 << 2)
3104a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_2	(3 << 2)
3105a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR			(0 << 0)
3106a0c29afbSChen-Yu Tsai #define OV5640_TEST_RANDOM		(1 << 0)
3107a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE		(2 << 0)
3108a0c29afbSChen-Yu Tsai #define OV5640_TEST_BLACK		(3 << 0)
3109a0c29afbSChen-Yu Tsai 
3110a0c29afbSChen-Yu Tsai static const u8 test_pattern_val[] = {
3111a0c29afbSChen-Yu Tsai 	0,
31122aff1fc3SChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_BAR_VERT_CHANGE_1 |
3113a0c29afbSChen-Yu Tsai 		OV5640_TEST_BAR,
3114bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_ROLLING |
3115bddc5cdfSChen-Yu Tsai 		OV5640_TEST_BAR_VERT_CHANGE_1 | OV5640_TEST_BAR,
3116bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_SQUARE,
3117bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_ROLLING | OV5640_TEST_SQUARE,
3118a0c29afbSChen-Yu Tsai };
3119a0c29afbSChen-Yu Tsai 
312019a81c14SSteve Longerbeam static int ov5640_set_ctrl_test_pattern(struct ov5640_dev *sensor, int value)
312119a81c14SSteve Longerbeam {
3122a0c29afbSChen-Yu Tsai 	return ov5640_write_reg(sensor, OV5640_REG_PRE_ISP_TEST_SET1,
3123a0c29afbSChen-Yu Tsai 				test_pattern_val[value]);
312419a81c14SSteve Longerbeam }
312519a81c14SSteve Longerbeam 
31261068fecaSMylène Josserand static int ov5640_set_ctrl_light_freq(struct ov5640_dev *sensor, int value)
31271068fecaSMylène Josserand {
31281068fecaSMylène Josserand 	int ret;
31291068fecaSMylène Josserand 
31301068fecaSMylène Josserand 	ret = ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL01, BIT(7),
31311068fecaSMylène Josserand 			     (value == V4L2_CID_POWER_LINE_FREQUENCY_AUTO) ?
31321068fecaSMylène Josserand 			     0 : BIT(7));
31331068fecaSMylène Josserand 	if (ret)
31341068fecaSMylène Josserand 		return ret;
31351068fecaSMylène Josserand 
31361068fecaSMylène Josserand 	return ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL00, BIT(2),
31371068fecaSMylène Josserand 			      (value == V4L2_CID_POWER_LINE_FREQUENCY_50HZ) ?
31381068fecaSMylène Josserand 			      BIT(2) : 0);
31391068fecaSMylène Josserand }
31401068fecaSMylène Josserand 
3141ce85705aSHugues Fruchet static int ov5640_set_ctrl_hflip(struct ov5640_dev *sensor, int value)
3142ce85705aSHugues Fruchet {
3143ce85705aSHugues Fruchet 	/*
3144c3f3ba3eSHugues Fruchet 	 * If sensor is mounted upside down, mirror logic is inversed.
3145c3f3ba3eSHugues Fruchet 	 *
3146ce85705aSHugues Fruchet 	 * Sensor is a BSI (Back Side Illuminated) one,
3147ce85705aSHugues Fruchet 	 * so image captured is physically mirrored.
3148ce85705aSHugues Fruchet 	 * This is why mirror logic is inversed in
3149ce85705aSHugues Fruchet 	 * order to cancel this mirror effect.
3150ce85705aSHugues Fruchet 	 */
3151ce85705aSHugues Fruchet 
3152ce85705aSHugues Fruchet 	/*
3153ce85705aSHugues Fruchet 	 * TIMING TC REG21:
3154ce85705aSHugues Fruchet 	 * - [2]:	ISP mirror
3155ce85705aSHugues Fruchet 	 * - [1]:	Sensor mirror
3156ce85705aSHugues Fruchet 	 */
3157ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
3158ce85705aSHugues Fruchet 			      BIT(2) | BIT(1),
3159c3f3ba3eSHugues Fruchet 			      (!(value ^ sensor->upside_down)) ?
3160c3f3ba3eSHugues Fruchet 			      (BIT(2) | BIT(1)) : 0);
3161ce85705aSHugues Fruchet }
3162ce85705aSHugues Fruchet 
3163ce85705aSHugues Fruchet static int ov5640_set_ctrl_vflip(struct ov5640_dev *sensor, int value)
3164ce85705aSHugues Fruchet {
3165c3f3ba3eSHugues Fruchet 	/* If sensor is mounted upside down, flip logic is inversed */
3166c3f3ba3eSHugues Fruchet 
3167ce85705aSHugues Fruchet 	/*
3168ce85705aSHugues Fruchet 	 * TIMING TC REG20:
3169ce85705aSHugues Fruchet 	 * - [2]:	ISP vflip
3170ce85705aSHugues Fruchet 	 * - [1]:	Sensor vflip
3171ce85705aSHugues Fruchet 	 */
3172ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20,
3173ce85705aSHugues Fruchet 			      BIT(2) | BIT(1),
3174c3f3ba3eSHugues Fruchet 			      (value ^ sensor->upside_down) ?
3175c3f3ba3eSHugues Fruchet 			      (BIT(2) | BIT(1)) : 0);
3176ce85705aSHugues Fruchet }
3177ce85705aSHugues Fruchet 
317819a81c14SSteve Longerbeam static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
317919a81c14SSteve Longerbeam {
318019a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
318119a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
318219a81c14SSteve Longerbeam 	int val;
318319a81c14SSteve Longerbeam 
318419a81c14SSteve Longerbeam 	/* v4l2_ctrl_lock() locks our own mutex */
318519a81c14SSteve Longerbeam 
318619a81c14SSteve Longerbeam 	switch (ctrl->id) {
318719a81c14SSteve Longerbeam 	case V4L2_CID_AUTOGAIN:
318819a81c14SSteve Longerbeam 		val = ov5640_get_gain(sensor);
318919a81c14SSteve Longerbeam 		if (val < 0)
319019a81c14SSteve Longerbeam 			return val;
319119a81c14SSteve Longerbeam 		sensor->ctrls.gain->val = val;
319219a81c14SSteve Longerbeam 		break;
319319a81c14SSteve Longerbeam 	case V4L2_CID_EXPOSURE_AUTO:
319419a81c14SSteve Longerbeam 		val = ov5640_get_exposure(sensor);
319519a81c14SSteve Longerbeam 		if (val < 0)
319619a81c14SSteve Longerbeam 			return val;
319719a81c14SSteve Longerbeam 		sensor->ctrls.exposure->val = val;
319819a81c14SSteve Longerbeam 		break;
319919a81c14SSteve Longerbeam 	}
320019a81c14SSteve Longerbeam 
320119a81c14SSteve Longerbeam 	return 0;
320219a81c14SSteve Longerbeam }
320319a81c14SSteve Longerbeam 
320419a81c14SSteve Longerbeam static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl)
320519a81c14SSteve Longerbeam {
320619a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
320719a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
320819a81c14SSteve Longerbeam 	int ret;
320919a81c14SSteve Longerbeam 
321019a81c14SSteve Longerbeam 	/* v4l2_ctrl_lock() locks our own mutex */
321119a81c14SSteve Longerbeam 
321219a81c14SSteve Longerbeam 	/*
321319a81c14SSteve Longerbeam 	 * If the device is not powered up by the host driver do
321419a81c14SSteve Longerbeam 	 * not apply any controls to H/W at this time. Instead
321519a81c14SSteve Longerbeam 	 * the controls will be restored right after power-up.
321619a81c14SSteve Longerbeam 	 */
321719a81c14SSteve Longerbeam 	if (sensor->power_count == 0)
321819a81c14SSteve Longerbeam 		return 0;
321919a81c14SSteve Longerbeam 
322019a81c14SSteve Longerbeam 	switch (ctrl->id) {
322119a81c14SSteve Longerbeam 	case V4L2_CID_AUTOGAIN:
322219a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_gain(sensor, ctrl->val);
322319a81c14SSteve Longerbeam 		break;
322419a81c14SSteve Longerbeam 	case V4L2_CID_EXPOSURE_AUTO:
322519a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_exposure(sensor, ctrl->val);
322619a81c14SSteve Longerbeam 		break;
322719a81c14SSteve Longerbeam 	case V4L2_CID_AUTO_WHITE_BALANCE:
322819a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_white_balance(sensor, ctrl->val);
322919a81c14SSteve Longerbeam 		break;
323019a81c14SSteve Longerbeam 	case V4L2_CID_HUE:
323119a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_hue(sensor, ctrl->val);
323219a81c14SSteve Longerbeam 		break;
323319a81c14SSteve Longerbeam 	case V4L2_CID_CONTRAST:
323419a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_contrast(sensor, ctrl->val);
323519a81c14SSteve Longerbeam 		break;
323619a81c14SSteve Longerbeam 	case V4L2_CID_SATURATION:
323719a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_saturation(sensor, ctrl->val);
323819a81c14SSteve Longerbeam 		break;
323919a81c14SSteve Longerbeam 	case V4L2_CID_TEST_PATTERN:
324019a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_test_pattern(sensor, ctrl->val);
324119a81c14SSteve Longerbeam 		break;
32421068fecaSMylène Josserand 	case V4L2_CID_POWER_LINE_FREQUENCY:
32431068fecaSMylène Josserand 		ret = ov5640_set_ctrl_light_freq(sensor, ctrl->val);
32441068fecaSMylène Josserand 		break;
3245ce85705aSHugues Fruchet 	case V4L2_CID_HFLIP:
3246ce85705aSHugues Fruchet 		ret = ov5640_set_ctrl_hflip(sensor, ctrl->val);
3247ce85705aSHugues Fruchet 		break;
3248ce85705aSHugues Fruchet 	case V4L2_CID_VFLIP:
3249ce85705aSHugues Fruchet 		ret = ov5640_set_ctrl_vflip(sensor, ctrl->val);
3250ce85705aSHugues Fruchet 		break;
325119a81c14SSteve Longerbeam 	default:
325219a81c14SSteve Longerbeam 		ret = -EINVAL;
325319a81c14SSteve Longerbeam 		break;
325419a81c14SSteve Longerbeam 	}
325519a81c14SSteve Longerbeam 
325619a81c14SSteve Longerbeam 	return ret;
325719a81c14SSteve Longerbeam }
325819a81c14SSteve Longerbeam 
325919a81c14SSteve Longerbeam static const struct v4l2_ctrl_ops ov5640_ctrl_ops = {
326019a81c14SSteve Longerbeam 	.g_volatile_ctrl = ov5640_g_volatile_ctrl,
326119a81c14SSteve Longerbeam 	.s_ctrl = ov5640_s_ctrl,
326219a81c14SSteve Longerbeam };
326319a81c14SSteve Longerbeam 
326419a81c14SSteve Longerbeam static int ov5640_init_controls(struct ov5640_dev *sensor)
326519a81c14SSteve Longerbeam {
326622845bf2SJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
326719a81c14SSteve Longerbeam 	const struct v4l2_ctrl_ops *ops = &ov5640_ctrl_ops;
326819a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
326919a81c14SSteve Longerbeam 	struct v4l2_ctrl_handler *hdl = &ctrls->handler;
327019a81c14SSteve Longerbeam 	int ret;
327119a81c14SSteve Longerbeam 
327219a81c14SSteve Longerbeam 	v4l2_ctrl_handler_init(hdl, 32);
327319a81c14SSteve Longerbeam 
327419a81c14SSteve Longerbeam 	/* we can use our own mutex for the ctrl lock */
327519a81c14SSteve Longerbeam 	hdl->lock = &sensor->lock;
327619a81c14SSteve Longerbeam 
3277cc196e48SBenoit Parrot 	/* Clock related controls */
3278cc196e48SBenoit Parrot 	ctrls->pixel_rate = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE,
327922845bf2SJacopo Mondi 			      ov5640_pixel_rates[OV5640_NUM_PIXEL_RATES - 1],
328022845bf2SJacopo Mondi 			      ov5640_pixel_rates[0], 1,
328122845bf2SJacopo Mondi 			      ov5640_pixel_rates[mode->pixel_rate]);
3282cc196e48SBenoit Parrot 
32837a3b8d4bSJacopo Mondi 	ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops,
32847a3b8d4bSJacopo Mondi 					V4L2_CID_LINK_FREQ,
32857a3b8d4bSJacopo Mondi 					ARRAY_SIZE(ov5640_csi2_link_freqs) - 1,
32867a3b8d4bSJacopo Mondi 					OV5640_DEFAULT_LINK_FREQ,
32877a3b8d4bSJacopo Mondi 					ov5640_csi2_link_freqs);
32887a3b8d4bSJacopo Mondi 
328919a81c14SSteve Longerbeam 	/* Auto/manual white balance */
329019a81c14SSteve Longerbeam 	ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops,
329119a81c14SSteve Longerbeam 					   V4L2_CID_AUTO_WHITE_BALANCE,
329219a81c14SSteve Longerbeam 					   0, 1, 1, 1);
329319a81c14SSteve Longerbeam 	ctrls->blue_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BLUE_BALANCE,
329419a81c14SSteve Longerbeam 						0, 4095, 1, 0);
329519a81c14SSteve Longerbeam 	ctrls->red_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_RED_BALANCE,
329619a81c14SSteve Longerbeam 					       0, 4095, 1, 0);
329719a81c14SSteve Longerbeam 	/* Auto/manual exposure */
329819a81c14SSteve Longerbeam 	ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops,
329919a81c14SSteve Longerbeam 						 V4L2_CID_EXPOSURE_AUTO,
330019a81c14SSteve Longerbeam 						 V4L2_EXPOSURE_MANUAL, 0,
330119a81c14SSteve Longerbeam 						 V4L2_EXPOSURE_AUTO);
330219a81c14SSteve Longerbeam 	ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
330319a81c14SSteve Longerbeam 					    0, 65535, 1, 0);
330419a81c14SSteve Longerbeam 	/* Auto/manual gain */
330519a81c14SSteve Longerbeam 	ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN,
330619a81c14SSteve Longerbeam 					     0, 1, 1, 1);
330719a81c14SSteve Longerbeam 	ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN,
330819a81c14SSteve Longerbeam 					0, 1023, 1, 0);
330919a81c14SSteve Longerbeam 
331019a81c14SSteve Longerbeam 	ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION,
331119a81c14SSteve Longerbeam 					      0, 255, 1, 64);
331219a81c14SSteve Longerbeam 	ctrls->hue = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HUE,
331319a81c14SSteve Longerbeam 				       0, 359, 1, 0);
331419a81c14SSteve Longerbeam 	ctrls->contrast = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST,
331519a81c14SSteve Longerbeam 					    0, 255, 1, 0);
331619a81c14SSteve Longerbeam 	ctrls->test_pattern =
331719a81c14SSteve Longerbeam 		v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN,
331819a81c14SSteve Longerbeam 					     ARRAY_SIZE(test_pattern_menu) - 1,
331919a81c14SSteve Longerbeam 					     0, 0, test_pattern_menu);
3320ce85705aSHugues Fruchet 	ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP,
3321ce85705aSHugues Fruchet 					 0, 1, 1, 0);
3322ce85705aSHugues Fruchet 	ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP,
3323ce85705aSHugues Fruchet 					 0, 1, 1, 0);
332419a81c14SSteve Longerbeam 
33251068fecaSMylène Josserand 	ctrls->light_freq =
33261068fecaSMylène Josserand 		v4l2_ctrl_new_std_menu(hdl, ops,
33271068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY,
33281068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
33291068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
33301068fecaSMylène Josserand 
333119a81c14SSteve Longerbeam 	if (hdl->error) {
333219a81c14SSteve Longerbeam 		ret = hdl->error;
333319a81c14SSteve Longerbeam 		goto free_ctrls;
333419a81c14SSteve Longerbeam 	}
333519a81c14SSteve Longerbeam 
3336cc196e48SBenoit Parrot 	ctrls->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY;
33377a3b8d4bSJacopo Mondi 	ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
333819a81c14SSteve Longerbeam 	ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE;
333919a81c14SSteve Longerbeam 	ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE;
334019a81c14SSteve Longerbeam 
334119a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false);
334219a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(2, &ctrls->auto_gain, 0, true);
334319a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(2, &ctrls->auto_exp, 1, true);
334419a81c14SSteve Longerbeam 
334519a81c14SSteve Longerbeam 	sensor->sd.ctrl_handler = hdl;
334619a81c14SSteve Longerbeam 	return 0;
334719a81c14SSteve Longerbeam 
334819a81c14SSteve Longerbeam free_ctrls:
334919a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(hdl);
335019a81c14SSteve Longerbeam 	return ret;
335119a81c14SSteve Longerbeam }
335219a81c14SSteve Longerbeam 
335319a81c14SSteve Longerbeam static int ov5640_enum_frame_size(struct v4l2_subdev *sd,
33540d346d2aSTomi Valkeinen 				  struct v4l2_subdev_state *sd_state,
335519a81c14SSteve Longerbeam 				  struct v4l2_subdev_frame_size_enum *fse)
335619a81c14SSteve Longerbeam {
335719a81c14SSteve Longerbeam 	if (fse->pad != 0)
335819a81c14SSteve Longerbeam 		return -EINVAL;
335919a81c14SSteve Longerbeam 	if (fse->index >= OV5640_NUM_MODES)
336019a81c14SSteve Longerbeam 		return -EINVAL;
336119a81c14SSteve Longerbeam 
33625113d5b3SJacopo Mondi 	fse->min_width = ov5640_mode_data[fse->index].width;
336341d8d7f5SHugues Fruchet 	fse->max_width = fse->min_width;
33645113d5b3SJacopo Mondi 	fse->min_height = ov5640_mode_data[fse->index].height;
336541d8d7f5SHugues Fruchet 	fse->max_height = fse->min_height;
336619a81c14SSteve Longerbeam 
336719a81c14SSteve Longerbeam 	return 0;
336819a81c14SSteve Longerbeam }
336919a81c14SSteve Longerbeam 
337019a81c14SSteve Longerbeam static int ov5640_enum_frame_interval(
337119a81c14SSteve Longerbeam 	struct v4l2_subdev *sd,
33720d346d2aSTomi Valkeinen 	struct v4l2_subdev_state *sd_state,
337319a81c14SSteve Longerbeam 	struct v4l2_subdev_frame_interval_enum *fie)
337419a81c14SSteve Longerbeam {
337519a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
337619a81c14SSteve Longerbeam 	struct v4l2_fract tpf;
337719a81c14SSteve Longerbeam 	int ret;
337819a81c14SSteve Longerbeam 
337919a81c14SSteve Longerbeam 	if (fie->pad != 0)
338019a81c14SSteve Longerbeam 		return -EINVAL;
338119a81c14SSteve Longerbeam 	if (fie->index >= OV5640_NUM_FRAMERATES)
338219a81c14SSteve Longerbeam 		return -EINVAL;
338319a81c14SSteve Longerbeam 
338419a81c14SSteve Longerbeam 	tpf.numerator = 1;
338519a81c14SSteve Longerbeam 	tpf.denominator = ov5640_framerates[fie->index];
338619a81c14SSteve Longerbeam 
338719a81c14SSteve Longerbeam 	ret = ov5640_try_frame_interval(sensor, &tpf,
338819a81c14SSteve Longerbeam 					fie->width, fie->height);
338919a81c14SSteve Longerbeam 	if (ret < 0)
339019a81c14SSteve Longerbeam 		return -EINVAL;
339119a81c14SSteve Longerbeam 
339219a81c14SSteve Longerbeam 	fie->interval = tpf;
339319a81c14SSteve Longerbeam 	return 0;
339419a81c14SSteve Longerbeam }
339519a81c14SSteve Longerbeam 
339619a81c14SSteve Longerbeam static int ov5640_g_frame_interval(struct v4l2_subdev *sd,
339719a81c14SSteve Longerbeam 				   struct v4l2_subdev_frame_interval *fi)
339819a81c14SSteve Longerbeam {
339919a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
340019a81c14SSteve Longerbeam 
340119a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
340219a81c14SSteve Longerbeam 	fi->interval = sensor->frame_interval;
340319a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
340419a81c14SSteve Longerbeam 
340519a81c14SSteve Longerbeam 	return 0;
340619a81c14SSteve Longerbeam }
340719a81c14SSteve Longerbeam 
340819a81c14SSteve Longerbeam static int ov5640_s_frame_interval(struct v4l2_subdev *sd,
340919a81c14SSteve Longerbeam 				   struct v4l2_subdev_frame_interval *fi)
341019a81c14SSteve Longerbeam {
341119a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
341219a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
341319a81c14SSteve Longerbeam 	int frame_rate, ret = 0;
341419a81c14SSteve Longerbeam 
341519a81c14SSteve Longerbeam 	if (fi->pad != 0)
341619a81c14SSteve Longerbeam 		return -EINVAL;
341719a81c14SSteve Longerbeam 
341819a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
341919a81c14SSteve Longerbeam 
342019a81c14SSteve Longerbeam 	if (sensor->streaming) {
342119a81c14SSteve Longerbeam 		ret = -EBUSY;
342219a81c14SSteve Longerbeam 		goto out;
342319a81c14SSteve Longerbeam 	}
342419a81c14SSteve Longerbeam 
342519a81c14SSteve Longerbeam 	mode = sensor->current_mode;
342619a81c14SSteve Longerbeam 
342719a81c14SSteve Longerbeam 	frame_rate = ov5640_try_frame_interval(sensor, &fi->interval,
34285113d5b3SJacopo Mondi 					       mode->width,
34295113d5b3SJacopo Mondi 					       mode->height);
3430e823fb16SMaxime Ripard 	if (frame_rate < 0) {
3431e823fb16SMaxime Ripard 		/* Always return a valid frame interval value */
3432e823fb16SMaxime Ripard 		fi->interval = sensor->frame_interval;
3433e823fb16SMaxime Ripard 		goto out;
3434e823fb16SMaxime Ripard 	}
343519a81c14SSteve Longerbeam 
34365113d5b3SJacopo Mondi 	mode = ov5640_find_mode(sensor, frame_rate, mode->width,
34375113d5b3SJacopo Mondi 				mode->height, true);
34383c4a7372SHugues Fruchet 	if (!mode) {
34393c4a7372SHugues Fruchet 		ret = -EINVAL;
34403c4a7372SHugues Fruchet 		goto out;
34413c4a7372SHugues Fruchet 	}
34423c4a7372SHugues Fruchet 
34430929983eSHugues Fruchet 	if (mode != sensor->current_mode ||
34440929983eSHugues Fruchet 	    frame_rate != sensor->current_fr) {
34450929983eSHugues Fruchet 		sensor->current_fr = frame_rate;
34460929983eSHugues Fruchet 		sensor->frame_interval = fi->interval;
34473c4a7372SHugues Fruchet 		sensor->current_mode = mode;
344819a81c14SSteve Longerbeam 		sensor->pending_mode_change = true;
3449cc196e48SBenoit Parrot 
3450cc196e48SBenoit Parrot 		__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate,
3451cc196e48SBenoit Parrot 					 ov5640_calc_pixel_rate(sensor));
34526949d864SHugues Fruchet 	}
345319a81c14SSteve Longerbeam out:
345419a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
345519a81c14SSteve Longerbeam 	return ret;
345619a81c14SSteve Longerbeam }
345719a81c14SSteve Longerbeam 
345819a81c14SSteve Longerbeam static int ov5640_enum_mbus_code(struct v4l2_subdev *sd,
34590d346d2aSTomi Valkeinen 				 struct v4l2_subdev_state *sd_state,
346019a81c14SSteve Longerbeam 				 struct v4l2_subdev_mbus_code_enum *code)
346119a81c14SSteve Longerbeam {
346219a81c14SSteve Longerbeam 	if (code->pad != 0)
346319a81c14SSteve Longerbeam 		return -EINVAL;
3464e3ee691dSHugues Fruchet 	if (code->index >= ARRAY_SIZE(ov5640_formats))
346519a81c14SSteve Longerbeam 		return -EINVAL;
346619a81c14SSteve Longerbeam 
3467e3ee691dSHugues Fruchet 	code->code = ov5640_formats[code->index].code;
346819a81c14SSteve Longerbeam 	return 0;
346919a81c14SSteve Longerbeam }
347019a81c14SSteve Longerbeam 
347119a81c14SSteve Longerbeam static int ov5640_s_stream(struct v4l2_subdev *sd, int enable)
347219a81c14SSteve Longerbeam {
347319a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
347419a81c14SSteve Longerbeam 	int ret = 0;
347519a81c14SSteve Longerbeam 
347619a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
347719a81c14SSteve Longerbeam 
347819a81c14SSteve Longerbeam 	if (sensor->streaming == !enable) {
347919a81c14SSteve Longerbeam 		if (enable && sensor->pending_mode_change) {
3480985cdcb0SHugues Fruchet 			ret = ov5640_set_mode(sensor);
348119a81c14SSteve Longerbeam 			if (ret)
348219a81c14SSteve Longerbeam 				goto out;
3483fb98e29fSHugues Fruchet 		}
3484e3ee691dSHugues Fruchet 
3485fb98e29fSHugues Fruchet 		if (enable && sensor->pending_fmt_change) {
3486e3ee691dSHugues Fruchet 			ret = ov5640_set_framefmt(sensor, &sensor->fmt);
3487e3ee691dSHugues Fruchet 			if (ret)
3488e3ee691dSHugues Fruchet 				goto out;
3489fb98e29fSHugues Fruchet 			sensor->pending_fmt_change = false;
349019a81c14SSteve Longerbeam 		}
349119a81c14SSteve Longerbeam 
34928e823f5cSJacopo Mondi 		if (ov5640_is_csi2(sensor))
3493f22996dbSHugues Fruchet 			ret = ov5640_set_stream_mipi(sensor, enable);
3494f22996dbSHugues Fruchet 		else
3495f22996dbSHugues Fruchet 			ret = ov5640_set_stream_dvp(sensor, enable);
3496f22996dbSHugues Fruchet 
349719a81c14SSteve Longerbeam 		if (!ret)
349819a81c14SSteve Longerbeam 			sensor->streaming = enable;
349919a81c14SSteve Longerbeam 	}
350019a81c14SSteve Longerbeam out:
350119a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
350219a81c14SSteve Longerbeam 	return ret;
350319a81c14SSteve Longerbeam }
350419a81c14SSteve Longerbeam 
350519a81c14SSteve Longerbeam static const struct v4l2_subdev_core_ops ov5640_core_ops = {
350619a81c14SSteve Longerbeam 	.s_power = ov5640_s_power,
35072d18fbc5SAkinobu Mita 	.log_status = v4l2_ctrl_subdev_log_status,
35082d18fbc5SAkinobu Mita 	.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
35092d18fbc5SAkinobu Mita 	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
351019a81c14SSteve Longerbeam };
351119a81c14SSteve Longerbeam 
351219a81c14SSteve Longerbeam static const struct v4l2_subdev_video_ops ov5640_video_ops = {
351319a81c14SSteve Longerbeam 	.g_frame_interval = ov5640_g_frame_interval,
351419a81c14SSteve Longerbeam 	.s_frame_interval = ov5640_s_frame_interval,
351519a81c14SSteve Longerbeam 	.s_stream = ov5640_s_stream,
351619a81c14SSteve Longerbeam };
351719a81c14SSteve Longerbeam 
351819a81c14SSteve Longerbeam static const struct v4l2_subdev_pad_ops ov5640_pad_ops = {
351919a81c14SSteve Longerbeam 	.enum_mbus_code = ov5640_enum_mbus_code,
352019a81c14SSteve Longerbeam 	.get_fmt = ov5640_get_fmt,
352119a81c14SSteve Longerbeam 	.set_fmt = ov5640_set_fmt,
352219a81c14SSteve Longerbeam 	.enum_frame_size = ov5640_enum_frame_size,
352319a81c14SSteve Longerbeam 	.enum_frame_interval = ov5640_enum_frame_interval,
352419a81c14SSteve Longerbeam };
352519a81c14SSteve Longerbeam 
352619a81c14SSteve Longerbeam static const struct v4l2_subdev_ops ov5640_subdev_ops = {
352719a81c14SSteve Longerbeam 	.core = &ov5640_core_ops,
352819a81c14SSteve Longerbeam 	.video = &ov5640_video_ops,
352919a81c14SSteve Longerbeam 	.pad = &ov5640_pad_ops,
353019a81c14SSteve Longerbeam };
353119a81c14SSteve Longerbeam 
353219a81c14SSteve Longerbeam static int ov5640_get_regulators(struct ov5640_dev *sensor)
353319a81c14SSteve Longerbeam {
353419a81c14SSteve Longerbeam 	int i;
353519a81c14SSteve Longerbeam 
353619a81c14SSteve Longerbeam 	for (i = 0; i < OV5640_NUM_SUPPLIES; i++)
353719a81c14SSteve Longerbeam 		sensor->supplies[i].supply = ov5640_supply_name[i];
353819a81c14SSteve Longerbeam 
353919a81c14SSteve Longerbeam 	return devm_regulator_bulk_get(&sensor->i2c_client->dev,
354019a81c14SSteve Longerbeam 				       OV5640_NUM_SUPPLIES,
354119a81c14SSteve Longerbeam 				       sensor->supplies);
354219a81c14SSteve Longerbeam }
354319a81c14SSteve Longerbeam 
35440f7acb52SHugues Fruchet static int ov5640_check_chip_id(struct ov5640_dev *sensor)
35450f7acb52SHugues Fruchet {
35460f7acb52SHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
35470f7acb52SHugues Fruchet 	int ret = 0;
35480f7acb52SHugues Fruchet 	u16 chip_id;
35490f7acb52SHugues Fruchet 
35500f7acb52SHugues Fruchet 	ret = ov5640_set_power_on(sensor);
35510f7acb52SHugues Fruchet 	if (ret)
35520f7acb52SHugues Fruchet 		return ret;
35530f7acb52SHugues Fruchet 
35540f7acb52SHugues Fruchet 	ret = ov5640_read_reg16(sensor, OV5640_REG_CHIP_ID, &chip_id);
35550f7acb52SHugues Fruchet 	if (ret) {
35560f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to read chip identifier\n",
35570f7acb52SHugues Fruchet 			__func__);
35580f7acb52SHugues Fruchet 		goto power_off;
35590f7acb52SHugues Fruchet 	}
35600f7acb52SHugues Fruchet 
35610f7acb52SHugues Fruchet 	if (chip_id != 0x5640) {
35620f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: wrong chip identifier, expected 0x5640, got 0x%x\n",
35630f7acb52SHugues Fruchet 			__func__, chip_id);
35640f7acb52SHugues Fruchet 		ret = -ENXIO;
35650f7acb52SHugues Fruchet 	}
35660f7acb52SHugues Fruchet 
35670f7acb52SHugues Fruchet power_off:
35680f7acb52SHugues Fruchet 	ov5640_set_power_off(sensor);
35690f7acb52SHugues Fruchet 	return ret;
35700f7acb52SHugues Fruchet }
35710f7acb52SHugues Fruchet 
3572e6714993SKieran Bingham static int ov5640_probe(struct i2c_client *client)
357319a81c14SSteve Longerbeam {
357419a81c14SSteve Longerbeam 	struct device *dev = &client->dev;
357519a81c14SSteve Longerbeam 	struct fwnode_handle *endpoint;
357619a81c14SSteve Longerbeam 	struct ov5640_dev *sensor;
3577e6441fdeSHugues Fruchet 	struct v4l2_mbus_framefmt *fmt;
3578c3f3ba3eSHugues Fruchet 	u32 rotation;
357919a81c14SSteve Longerbeam 	int ret;
358019a81c14SSteve Longerbeam 
358119a81c14SSteve Longerbeam 	sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
358219a81c14SSteve Longerbeam 	if (!sensor)
358319a81c14SSteve Longerbeam 		return -ENOMEM;
358419a81c14SSteve Longerbeam 
358519a81c14SSteve Longerbeam 	sensor->i2c_client = client;
3586fb98e29fSHugues Fruchet 
3587fb98e29fSHugues Fruchet 	/*
3588fb98e29fSHugues Fruchet 	 * default init sequence initialize sensor to
3589fb98e29fSHugues Fruchet 	 * YUV422 UYVY VGA@30fps
3590fb98e29fSHugues Fruchet 	 */
3591e6441fdeSHugues Fruchet 	fmt = &sensor->fmt;
3592fb98e29fSHugues Fruchet 	fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
3593fb98e29fSHugues Fruchet 	fmt->colorspace = V4L2_COLORSPACE_SRGB;
3594e6441fdeSHugues Fruchet 	fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
3595e6441fdeSHugues Fruchet 	fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
3596e6441fdeSHugues Fruchet 	fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
3597e6441fdeSHugues Fruchet 	fmt->width = 640;
3598e6441fdeSHugues Fruchet 	fmt->height = 480;
3599e6441fdeSHugues Fruchet 	fmt->field = V4L2_FIELD_NONE;
360019a81c14SSteve Longerbeam 	sensor->frame_interval.numerator = 1;
360119a81c14SSteve Longerbeam 	sensor->frame_interval.denominator = ov5640_framerates[OV5640_30_FPS];
360219a81c14SSteve Longerbeam 	sensor->current_fr = OV5640_30_FPS;
360319a81c14SSteve Longerbeam 	sensor->current_mode =
3604086c25f8SMaxime Ripard 		&ov5640_mode_data[OV5640_MODE_VGA_640_480];
3605985cdcb0SHugues Fruchet 	sensor->last_mode = sensor->current_mode;
36063c28588fSJacopo Mondi 	sensor->current_link_freq = OV5640_DEFAULT_LINK_FREQ;
360719a81c14SSteve Longerbeam 
360819a81c14SSteve Longerbeam 	sensor->ae_target = 52;
360919a81c14SSteve Longerbeam 
3610c3f3ba3eSHugues Fruchet 	/* optional indication of physical rotation of sensor */
3611c3f3ba3eSHugues Fruchet 	ret = fwnode_property_read_u32(dev_fwnode(&client->dev), "rotation",
3612c3f3ba3eSHugues Fruchet 				       &rotation);
3613c3f3ba3eSHugues Fruchet 	if (!ret) {
3614c3f3ba3eSHugues Fruchet 		switch (rotation) {
3615c3f3ba3eSHugues Fruchet 		case 180:
3616c3f3ba3eSHugues Fruchet 			sensor->upside_down = true;
36171771e9fbSGustavo A. R. Silva 			fallthrough;
3618c3f3ba3eSHugues Fruchet 		case 0:
3619c3f3ba3eSHugues Fruchet 			break;
3620c3f3ba3eSHugues Fruchet 		default:
3621c3f3ba3eSHugues Fruchet 			dev_warn(dev, "%u degrees rotation is not supported, ignoring...\n",
3622c3f3ba3eSHugues Fruchet 				 rotation);
3623c3f3ba3eSHugues Fruchet 		}
3624c3f3ba3eSHugues Fruchet 	}
3625c3f3ba3eSHugues Fruchet 
3626ce96bcf5SSakari Ailus 	endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev),
3627ce96bcf5SSakari Ailus 						  NULL);
362819a81c14SSteve Longerbeam 	if (!endpoint) {
362919a81c14SSteve Longerbeam 		dev_err(dev, "endpoint node not found\n");
363019a81c14SSteve Longerbeam 		return -EINVAL;
363119a81c14SSteve Longerbeam 	}
363219a81c14SSteve Longerbeam 
363319a81c14SSteve Longerbeam 	ret = v4l2_fwnode_endpoint_parse(endpoint, &sensor->ep);
363419a81c14SSteve Longerbeam 	fwnode_handle_put(endpoint);
363519a81c14SSteve Longerbeam 	if (ret) {
363619a81c14SSteve Longerbeam 		dev_err(dev, "Could not parse endpoint\n");
363719a81c14SSteve Longerbeam 		return ret;
363819a81c14SSteve Longerbeam 	}
363919a81c14SSteve Longerbeam 
36402c61e48dSLad Prabhakar 	if (sensor->ep.bus_type != V4L2_MBUS_PARALLEL &&
36412c61e48dSLad Prabhakar 	    sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY &&
36422c61e48dSLad Prabhakar 	    sensor->ep.bus_type != V4L2_MBUS_BT656) {
36432c61e48dSLad Prabhakar 		dev_err(dev, "Unsupported bus type %d\n", sensor->ep.bus_type);
36442c61e48dSLad Prabhakar 		return -EINVAL;
36452c61e48dSLad Prabhakar 	}
36462c61e48dSLad Prabhakar 
364719a81c14SSteve Longerbeam 	/* get system clock (xclk) */
364819a81c14SSteve Longerbeam 	sensor->xclk = devm_clk_get(dev, "xclk");
364919a81c14SSteve Longerbeam 	if (IS_ERR(sensor->xclk)) {
365019a81c14SSteve Longerbeam 		dev_err(dev, "failed to get xclk\n");
365119a81c14SSteve Longerbeam 		return PTR_ERR(sensor->xclk);
365219a81c14SSteve Longerbeam 	}
365319a81c14SSteve Longerbeam 
365419a81c14SSteve Longerbeam 	sensor->xclk_freq = clk_get_rate(sensor->xclk);
365519a81c14SSteve Longerbeam 	if (sensor->xclk_freq < OV5640_XCLK_MIN ||
365619a81c14SSteve Longerbeam 	    sensor->xclk_freq > OV5640_XCLK_MAX) {
365719a81c14SSteve Longerbeam 		dev_err(dev, "xclk frequency out of range: %d Hz\n",
365819a81c14SSteve Longerbeam 			sensor->xclk_freq);
365919a81c14SSteve Longerbeam 		return -EINVAL;
366019a81c14SSteve Longerbeam 	}
366119a81c14SSteve Longerbeam 
366219a81c14SSteve Longerbeam 	/* request optional power down pin */
366319a81c14SSteve Longerbeam 	sensor->pwdn_gpio = devm_gpiod_get_optional(dev, "powerdown",
366419a81c14SSteve Longerbeam 						    GPIOD_OUT_HIGH);
36658791a102SFabio Estevam 	if (IS_ERR(sensor->pwdn_gpio))
36668791a102SFabio Estevam 		return PTR_ERR(sensor->pwdn_gpio);
36678791a102SFabio Estevam 
366819a81c14SSteve Longerbeam 	/* request optional reset pin */
366919a81c14SSteve Longerbeam 	sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset",
367019a81c14SSteve Longerbeam 						     GPIOD_OUT_HIGH);
36718791a102SFabio Estevam 	if (IS_ERR(sensor->reset_gpio))
36728791a102SFabio Estevam 		return PTR_ERR(sensor->reset_gpio);
367319a81c14SSteve Longerbeam 
367419a81c14SSteve Longerbeam 	v4l2_i2c_subdev_init(&sensor->sd, client, &ov5640_subdev_ops);
367519a81c14SSteve Longerbeam 
36762d18fbc5SAkinobu Mita 	sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
36772d18fbc5SAkinobu Mita 			    V4L2_SUBDEV_FL_HAS_EVENTS;
367819a81c14SSteve Longerbeam 	sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
367919a81c14SSteve Longerbeam 	sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
368019a81c14SSteve Longerbeam 	ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
368119a81c14SSteve Longerbeam 	if (ret)
368219a81c14SSteve Longerbeam 		return ret;
368319a81c14SSteve Longerbeam 
368419a81c14SSteve Longerbeam 	ret = ov5640_get_regulators(sensor);
368519a81c14SSteve Longerbeam 	if (ret)
368619a81c14SSteve Longerbeam 		return ret;
368719a81c14SSteve Longerbeam 
368819a81c14SSteve Longerbeam 	mutex_init(&sensor->lock);
368919a81c14SSteve Longerbeam 
36900f7acb52SHugues Fruchet 	ret = ov5640_check_chip_id(sensor);
36910f7acb52SHugues Fruchet 	if (ret)
36920f7acb52SHugues Fruchet 		goto entity_cleanup;
36930f7acb52SHugues Fruchet 
369419a81c14SSteve Longerbeam 	ret = ov5640_init_controls(sensor);
369519a81c14SSteve Longerbeam 	if (ret)
369619a81c14SSteve Longerbeam 		goto entity_cleanup;
369719a81c14SSteve Longerbeam 
369815786f7bSSakari Ailus 	ret = v4l2_async_register_subdev_sensor(&sensor->sd);
369919a81c14SSteve Longerbeam 	if (ret)
370019a81c14SSteve Longerbeam 		goto free_ctrls;
370119a81c14SSteve Longerbeam 
370219a81c14SSteve Longerbeam 	return 0;
370319a81c14SSteve Longerbeam 
370419a81c14SSteve Longerbeam free_ctrls:
370519a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
370619a81c14SSteve Longerbeam entity_cleanup:
370719a81c14SSteve Longerbeam 	media_entity_cleanup(&sensor->sd.entity);
3708bfcba38dSTomi Valkeinen 	mutex_destroy(&sensor->lock);
370919a81c14SSteve Longerbeam 	return ret;
371019a81c14SSteve Longerbeam }
371119a81c14SSteve Longerbeam 
371219a81c14SSteve Longerbeam static int ov5640_remove(struct i2c_client *client)
371319a81c14SSteve Longerbeam {
371419a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
371519a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
371619a81c14SSteve Longerbeam 
371719a81c14SSteve Longerbeam 	v4l2_async_unregister_subdev(&sensor->sd);
371819a81c14SSteve Longerbeam 	media_entity_cleanup(&sensor->sd.entity);
371919a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
3720bfcba38dSTomi Valkeinen 	mutex_destroy(&sensor->lock);
372119a81c14SSteve Longerbeam 
372219a81c14SSteve Longerbeam 	return 0;
372319a81c14SSteve Longerbeam }
372419a81c14SSteve Longerbeam 
372519a81c14SSteve Longerbeam static const struct i2c_device_id ov5640_id[] = {
372619a81c14SSteve Longerbeam 	{"ov5640", 0},
372719a81c14SSteve Longerbeam 	{},
372819a81c14SSteve Longerbeam };
372919a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(i2c, ov5640_id);
373019a81c14SSteve Longerbeam 
373119a81c14SSteve Longerbeam static const struct of_device_id ov5640_dt_ids[] = {
373219a81c14SSteve Longerbeam 	{ .compatible = "ovti,ov5640" },
373319a81c14SSteve Longerbeam 	{ /* sentinel */ }
373419a81c14SSteve Longerbeam };
373519a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(of, ov5640_dt_ids);
373619a81c14SSteve Longerbeam 
373719a81c14SSteve Longerbeam static struct i2c_driver ov5640_i2c_driver = {
373819a81c14SSteve Longerbeam 	.driver = {
373919a81c14SSteve Longerbeam 		.name  = "ov5640",
374019a81c14SSteve Longerbeam 		.of_match_table	= ov5640_dt_ids,
374119a81c14SSteve Longerbeam 	},
374219a81c14SSteve Longerbeam 	.id_table = ov5640_id,
3743e6714993SKieran Bingham 	.probe_new = ov5640_probe,
374419a81c14SSteve Longerbeam 	.remove   = ov5640_remove,
374519a81c14SSteve Longerbeam };
374619a81c14SSteve Longerbeam 
374719a81c14SSteve Longerbeam module_i2c_driver(ov5640_i2c_driver);
374819a81c14SSteve Longerbeam 
374919a81c14SSteve Longerbeam MODULE_DESCRIPTION("OV5640 MIPI Camera Subdev Driver");
375019a81c14SSteve Longerbeam MODULE_LICENSE("GPL");
3751