xref: /openbmc/linux/drivers/media/i2c/ov5640.c (revision 2de6bb97)
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 
487086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_VGA_640_480[] = {
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},
49819a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
49919a81c14SSteve Longerbeam 	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
50019a81c14SSteve Longerbeam };
50119a81c14SSteve Longerbeam 
502086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_XGA_1024_768[] = {
503c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
50419a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
505ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
5063145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
50719a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
50819a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
50919a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
51019a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
51119a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5122b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
51319a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
51486633417SMaxime Ripard 	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
51519a81c14SSteve Longerbeam };
51619a81c14SSteve Longerbeam 
517086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_QVGA_320_240[] = {
518c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
51919a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
520ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
5213145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
52219a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
52319a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
52419a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
52519a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
52619a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5272b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
52819a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
52919a81c14SSteve Longerbeam 	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
53019a81c14SSteve Longerbeam };
53119a81c14SSteve Longerbeam 
53232ea5e05SHugues Fruchet static const struct reg_value ov5640_setting_QQVGA_160_120[] = {
53332ea5e05SHugues Fruchet 	{0x3c07, 0x08, 0, 0},
53432ea5e05SHugues Fruchet 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
53532ea5e05SHugues Fruchet 	{0x3814, 0x31, 0, 0},
5363145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
53732ea5e05SHugues Fruchet 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
53832ea5e05SHugues Fruchet 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
53932ea5e05SHugues Fruchet 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
54032ea5e05SHugues Fruchet 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
54132ea5e05SHugues Fruchet 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
54232ea5e05SHugues Fruchet 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
54332ea5e05SHugues Fruchet 	{0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0},
54432ea5e05SHugues Fruchet };
54532ea5e05SHugues Fruchet 
546086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_QCIF_176_144[] = {
547c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
54819a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
549ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
5503145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
55119a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
55219a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
55319a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
55419a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
55519a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5562b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
55719a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
55819a81c14SSteve Longerbeam 	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
55919a81c14SSteve Longerbeam };
56019a81c14SSteve Longerbeam 
561086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_NTSC_720_480[] = {
562c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
56319a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
564ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
5653145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
56619a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
56719a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
56819a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
56919a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
57019a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5712b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
57219a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
57319a81c14SSteve Longerbeam 	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
57419a81c14SSteve Longerbeam };
57519a81c14SSteve Longerbeam 
576086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_PAL_720_576[] = {
577c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
57819a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
579ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
5803145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
58119a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
58219a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
58319a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
58419a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
58519a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5862b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
58719a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
58819a81c14SSteve Longerbeam 	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
58919a81c14SSteve Longerbeam };
59019a81c14SSteve Longerbeam 
591086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_720P_1280_720[] = {
592c14d107eSMaxime Ripard 	{0x3c07, 0x07, 0, 0},
59319a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
594ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
5953145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
59619a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
59719a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0},
59819a81c14SSteve Longerbeam 	{0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0},
59919a81c14SSteve Longerbeam 	{0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0},
60019a81c14SSteve Longerbeam 	{0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0},
6012b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
60219a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
60319a81c14SSteve Longerbeam 	{0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0},
60419a81c14SSteve Longerbeam };
60519a81c14SSteve Longerbeam 
606086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_1080P_1920_1080[] = {
607c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
60819a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
609ce85705aSHugues Fruchet 	{0x3814, 0x11, 0, 0},
6103145efcdSJacopo Mondi 	{0x3815, 0x11, 0, 0},
61119a81c14SSteve Longerbeam 	{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
61219a81c14SSteve Longerbeam 	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
61319a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
61419a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
61519a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
6162b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0},
61719a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
618c14d107eSMaxime Ripard 	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0},
619c14d107eSMaxime Ripard 	{0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0},
62019a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
621476dec01SMaxime Ripard 	{0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0},
62219a81c14SSteve Longerbeam 	{0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0},
62319a81c14SSteve Longerbeam 	{0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0},
62419a81c14SSteve Longerbeam 	{0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0},
6252b5c18f9SChen-Yu Tsai 	{0x3a15, 0x60, 0, 0}, {0x4407, 0x04, 0, 0},
62619a81c14SSteve Longerbeam 	{0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0},
62792b9096cSBenoit Parrot 	{0x4005, 0x1a, 0, 0},
62819a81c14SSteve Longerbeam };
62919a81c14SSteve Longerbeam 
630086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_QSXGA_2592_1944[] = {
631c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
63219a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
633ce85705aSHugues Fruchet 	{0x3814, 0x11, 0, 0},
6343145efcdSJacopo Mondi 	{0x3815, 0x11, 0, 0},
63519a81c14SSteve Longerbeam 	{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
63619a81c14SSteve Longerbeam 	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
63719a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
63819a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
63919a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
6402b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0},
64119a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
64219a81c14SSteve Longerbeam 	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70},
64319a81c14SSteve Longerbeam };
64419a81c14SSteve Longerbeam 
64519a81c14SSteve Longerbeam /* power-on sensor init reg table */
64619a81c14SSteve Longerbeam static const struct ov5640_mode_info ov5640_mode_init_data = {
6473145efcdSJacopo Mondi 		.id		= 0,
6483145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
6493145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
6505113d5b3SJacopo Mondi 		.width	= 640,
6515113d5b3SJacopo Mondi 		.height	= 480,
6525113d5b3SJacopo Mondi 		.dvp_timings = {
6533145efcdSJacopo Mondi 			.analog_crop = {
6543145efcdSJacopo Mondi 				.left	= 0,
6553145efcdSJacopo Mondi 				.top	= 4,
6563145efcdSJacopo Mondi 				.width	= 2624,
6573145efcdSJacopo Mondi 				.height	= 1944,
6583145efcdSJacopo Mondi 			},
6593145efcdSJacopo Mondi 			.crop = {
6603145efcdSJacopo Mondi 				.left	= 16,
6613145efcdSJacopo Mondi 				.top	= 6,
6623145efcdSJacopo Mondi 				.width	= 640,
6633145efcdSJacopo Mondi 				.height	= 480,
6643145efcdSJacopo Mondi 			},
6653145efcdSJacopo Mondi 			.htot		= 1896,
6663145efcdSJacopo Mondi 			.vblank_def	= 504,
6675113d5b3SJacopo Mondi 		},
6685113d5b3SJacopo Mondi 		.csi2_timings = {
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 			.crop = {
6765113d5b3SJacopo Mondi 				.left	= 2,
6775113d5b3SJacopo Mondi 				.top	= 4,
6785113d5b3SJacopo Mondi 				.width	= 640,
6795113d5b3SJacopo Mondi 				.height	= 480,
6805113d5b3SJacopo Mondi 			},
6815113d5b3SJacopo Mondi 			.htot		= 1896,
6825113d5b3SJacopo Mondi 			.vblank_def	= 504,
6835113d5b3SJacopo Mondi 		},
6843145efcdSJacopo Mondi 		.reg_data	= ov5640_init_setting_30fps_VGA,
6853145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_init_setting_30fps_VGA),
6863145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
68719a81c14SSteve Longerbeam };
68819a81c14SSteve Longerbeam 
6895113d5b3SJacopo Mondi static const struct ov5640_mode_info ov5640_mode_data[OV5640_NUM_MODES] = {
6908409d017SJacopo Mondi 	{
6918409d017SJacopo Mondi 		/* 160x120 */
6923145efcdSJacopo Mondi 		.id		= OV5640_MODE_QQVGA_160_120,
6933145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
6943145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
6955113d5b3SJacopo Mondi 		.width		= 160,
6965113d5b3SJacopo Mondi 		.height		= 120,
6975113d5b3SJacopo Mondi 		.dvp_timings = {
6983145efcdSJacopo Mondi 			.analog_crop = {
6993145efcdSJacopo Mondi 				.left	= 0,
7003145efcdSJacopo Mondi 				.top	= 4,
7013145efcdSJacopo Mondi 				.width	= 2624,
7023145efcdSJacopo Mondi 				.height	= 1944,
7033145efcdSJacopo Mondi 			},
7043145efcdSJacopo Mondi 			.crop = {
7053145efcdSJacopo Mondi 				.left	= 16,
7063145efcdSJacopo Mondi 				.top	= 6,
7073145efcdSJacopo Mondi 				.width	= 160,
7083145efcdSJacopo Mondi 				.height	= 120,
7093145efcdSJacopo Mondi 			},
7103145efcdSJacopo Mondi 			.htot		= 1896,
7113145efcdSJacopo Mondi 			.vblank_def	= 864,
7125113d5b3SJacopo Mondi 		},
7135113d5b3SJacopo Mondi 		.csi2_timings = {
7145113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
7155113d5b3SJacopo Mondi 			.analog_crop = {
7165113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
7175113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
7185113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
7195113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
7205113d5b3SJacopo Mondi 			},
7215113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
7225113d5b3SJacopo Mondi 			.crop = {
7235113d5b3SJacopo Mondi 				.left	= 2,
7245113d5b3SJacopo Mondi 				.top	= 4,
7255113d5b3SJacopo Mondi 				.width	= 160,
7265113d5b3SJacopo Mondi 				.height	= 120,
7275113d5b3SJacopo Mondi 			},
7285113d5b3SJacopo Mondi 			.htot		= 1896,
7295113d5b3SJacopo Mondi 			.vblank_def	= 864,
7305113d5b3SJacopo Mondi 		},
7313145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_QQVGA_160_120,
7323145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_QQVGA_160_120),
7333145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
7348409d017SJacopo Mondi 	}, {
7358409d017SJacopo Mondi 		/* 176x144 */
7363145efcdSJacopo Mondi 		.id		= OV5640_MODE_QCIF_176_144,
7373145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
7383145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
7395113d5b3SJacopo Mondi 		.width		= 176,
7405113d5b3SJacopo Mondi 		.height		= 144,
7415113d5b3SJacopo Mondi 		.dvp_timings = {
7423145efcdSJacopo Mondi 			.analog_crop = {
7433145efcdSJacopo Mondi 				.left	= 0,
7443145efcdSJacopo Mondi 				.top	= 4,
7453145efcdSJacopo Mondi 				.width	= 2624,
7463145efcdSJacopo Mondi 				.height	= 1944,
7473145efcdSJacopo Mondi 			},
7483145efcdSJacopo Mondi 			.crop = {
7493145efcdSJacopo Mondi 				.left	= 16,
7503145efcdSJacopo Mondi 				.top	= 6,
7513145efcdSJacopo Mondi 				.width	= 176,
7523145efcdSJacopo Mondi 				.height	= 144,
7533145efcdSJacopo Mondi 			},
7543145efcdSJacopo Mondi 			.htot		= 1896,
7553145efcdSJacopo Mondi 			.vblank_def	= 840,
7565113d5b3SJacopo Mondi 		},
7575113d5b3SJacopo Mondi 		.csi2_timings = {
7585113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
7595113d5b3SJacopo Mondi 			.analog_crop = {
7605113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
7615113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
7625113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
7635113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
7645113d5b3SJacopo Mondi 			},
7655113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
7665113d5b3SJacopo Mondi 			.crop = {
7675113d5b3SJacopo Mondi 				.left	= 2,
7685113d5b3SJacopo Mondi 				.top	= 4,
7695113d5b3SJacopo Mondi 				.width	= 176,
7705113d5b3SJacopo Mondi 				.height	= 144,
7715113d5b3SJacopo Mondi 			},
7725113d5b3SJacopo Mondi 			.htot		= 1896,
7735113d5b3SJacopo Mondi 			.vblank_def	= 840,
7745113d5b3SJacopo Mondi 		},
7753145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_QCIF_176_144,
7763145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_QCIF_176_144),
7773145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
7788409d017SJacopo Mondi 	}, {
7798409d017SJacopo Mondi 		/* 320x240 */
7803145efcdSJacopo Mondi 		.id		= OV5640_MODE_QVGA_320_240,
7813145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
7825113d5b3SJacopo Mondi 		.width		= 320,
7835113d5b3SJacopo Mondi 		.height		= 240,
7843145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
7855113d5b3SJacopo Mondi 		.dvp_timings = {
7863145efcdSJacopo Mondi 			.analog_crop = {
7873145efcdSJacopo Mondi 				.left	= 0,
7883145efcdSJacopo Mondi 				.top	= 4,
7893145efcdSJacopo Mondi 				.width	= 2624,
7903145efcdSJacopo Mondi 				.height	= 1944,
7913145efcdSJacopo Mondi 			},
7923145efcdSJacopo Mondi 			.crop = {
7933145efcdSJacopo Mondi 				.left	= 16,
7943145efcdSJacopo Mondi 				.top	= 6,
7953145efcdSJacopo Mondi 				.width	= 320,
7963145efcdSJacopo Mondi 				.height	= 240,
7973145efcdSJacopo Mondi 			},
7983145efcdSJacopo Mondi 			.htot		= 1896,
7993145efcdSJacopo Mondi 			.vblank_def	= 744,
8005113d5b3SJacopo Mondi 		},
8015113d5b3SJacopo Mondi 		.csi2_timings = {
8025113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
8035113d5b3SJacopo Mondi 			.analog_crop = {
8045113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
8055113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
8065113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
8075113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
8085113d5b3SJacopo Mondi 			},
8095113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
8105113d5b3SJacopo Mondi 			.crop = {
8115113d5b3SJacopo Mondi 				.left	= 2,
8125113d5b3SJacopo Mondi 				.top	= 4,
8135113d5b3SJacopo Mondi 				.width	= 320,
8145113d5b3SJacopo Mondi 				.height	= 240,
8155113d5b3SJacopo Mondi 			},
8165113d5b3SJacopo Mondi 			.htot		= 1896,
8175113d5b3SJacopo Mondi 			.vblank_def	= 744,
8185113d5b3SJacopo Mondi 		},
8193145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_QVGA_320_240,
8203145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_QVGA_320_240),
8213145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
8228409d017SJacopo Mondi 	}, {
8238409d017SJacopo Mondi 		/* 640x480 */
8243145efcdSJacopo Mondi 		.id		= OV5640_MODE_VGA_640_480,
8253145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
8263145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
8275113d5b3SJacopo Mondi 		.width		= 640,
8285113d5b3SJacopo Mondi 		.height		= 480,
8295113d5b3SJacopo Mondi 		.dvp_timings = {
8303145efcdSJacopo Mondi 			.analog_crop = {
8313145efcdSJacopo Mondi 				.left	= 0,
8323145efcdSJacopo Mondi 				.top	= 4,
8333145efcdSJacopo Mondi 				.width	= 2624,
8343145efcdSJacopo Mondi 				.height	= 1944,
8353145efcdSJacopo Mondi 			},
8363145efcdSJacopo Mondi 			.crop = {
8373145efcdSJacopo Mondi 				.left	= 16,
8383145efcdSJacopo Mondi 				.top	= 6,
8393145efcdSJacopo Mondi 				.width	= 640,
8403145efcdSJacopo Mondi 				.height	= 480,
8413145efcdSJacopo Mondi 			},
8423145efcdSJacopo Mondi 			.htot		= 1896,
8433145efcdSJacopo Mondi 			.vblank_def	= 600,
8445113d5b3SJacopo Mondi 		},
8455113d5b3SJacopo Mondi 		.csi2_timings = {
8465113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
8475113d5b3SJacopo Mondi 			.analog_crop = {
8485113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
8495113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
8505113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
8515113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
8525113d5b3SJacopo Mondi 			},
8535113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
8545113d5b3SJacopo Mondi 			.crop = {
8555113d5b3SJacopo Mondi 				.left	= 2,
8565113d5b3SJacopo Mondi 				.top	= 4,
8575113d5b3SJacopo Mondi 				.width	= 640,
8585113d5b3SJacopo Mondi 				.height	= 480,
8595113d5b3SJacopo Mondi 			},
8605113d5b3SJacopo Mondi 			.htot		= 1896,
8615113d5b3SJacopo Mondi 			.vblank_def	= 600,
8625113d5b3SJacopo Mondi 		},
8633145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_VGA_640_480,
8643145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_VGA_640_480),
8653145efcdSJacopo Mondi 		.max_fps	= OV5640_60_FPS
8668409d017SJacopo Mondi 	}, {
8678409d017SJacopo Mondi 		/* 720x480 */
8683145efcdSJacopo Mondi 		.id		= OV5640_MODE_NTSC_720_480,
8693145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
8705113d5b3SJacopo Mondi 		.width		= 720,
8715113d5b3SJacopo Mondi 		.height		= 480,
8723145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
8735113d5b3SJacopo Mondi 		.dvp_timings = {
8743145efcdSJacopo Mondi 			.analog_crop = {
8753145efcdSJacopo Mondi 				.left	= 0,
8763145efcdSJacopo Mondi 				.top	= 4,
8773145efcdSJacopo Mondi 				.width	= 2624,
8783145efcdSJacopo Mondi 				.height	= 1944,
8793145efcdSJacopo Mondi 			},
8803145efcdSJacopo Mondi 			.crop = {
881e74ef55bSJacopo Mondi 				.left	= 56,
8823145efcdSJacopo Mondi 				.top	= 60,
8833145efcdSJacopo Mondi 				.width	= 720,
8843145efcdSJacopo Mondi 				.height	= 480,
8853145efcdSJacopo Mondi 			},
8863145efcdSJacopo Mondi 			.htot		= 1896,
8873145efcdSJacopo Mondi 			.vblank_def	= 504,
8885113d5b3SJacopo Mondi 		},
8895113d5b3SJacopo Mondi 		.csi2_timings = {
8905113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
8915113d5b3SJacopo Mondi 			.analog_crop = {
8925113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
8935113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
8945113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
8955113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
8965113d5b3SJacopo Mondi 			},
8975113d5b3SJacopo Mondi 			.crop = {
8985113d5b3SJacopo Mondi 				.left	= 56,
8995113d5b3SJacopo Mondi 				.top	= 60,
9005113d5b3SJacopo Mondi 				.width	= 720,
9015113d5b3SJacopo Mondi 				.height	= 480,
9025113d5b3SJacopo Mondi 			},
9035113d5b3SJacopo Mondi 			.htot		= 1896,
9045113d5b3SJacopo Mondi 			.vblank_def	= 504,
9055113d5b3SJacopo Mondi 		},
9063145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_NTSC_720_480,
9073145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_NTSC_720_480),
9083145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
9098409d017SJacopo Mondi 	}, {
9108409d017SJacopo Mondi 		/* 720x576 */
9113145efcdSJacopo Mondi 		.id		= OV5640_MODE_PAL_720_576,
9123145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
9135113d5b3SJacopo Mondi 		.width		= 720,
9145113d5b3SJacopo Mondi 		.height		= 576,
9153145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
9165113d5b3SJacopo Mondi 		.dvp_timings = {
9173145efcdSJacopo Mondi 			.analog_crop = {
9183145efcdSJacopo Mondi 				.left	= 0,
9193145efcdSJacopo Mondi 				.top	= 4,
9203145efcdSJacopo Mondi 				.width	= 2624,
9213145efcdSJacopo Mondi 				.height	= 1944,
9223145efcdSJacopo Mondi 			},
9233145efcdSJacopo Mondi 			.crop = {
9243145efcdSJacopo Mondi 				.left	= 56,
9253145efcdSJacopo Mondi 				.top	= 6,
9263145efcdSJacopo Mondi 				.width	= 720,
9273145efcdSJacopo Mondi 				.height	= 576,
9283145efcdSJacopo Mondi 			},
9293145efcdSJacopo Mondi 			.htot		= 1896,
9303145efcdSJacopo Mondi 			.vblank_def	= 408,
9315113d5b3SJacopo Mondi 		},
9325113d5b3SJacopo Mondi 		.csi2_timings = {
9335113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
9345113d5b3SJacopo Mondi 			.analog_crop = {
9355113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
9365113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
9375113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
9385113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
9395113d5b3SJacopo Mondi 			},
9405113d5b3SJacopo Mondi 			.crop = {
9415113d5b3SJacopo Mondi 				.left	= 56,
9425113d5b3SJacopo Mondi 				.top	= 6,
9435113d5b3SJacopo Mondi 				.width	= 720,
9445113d5b3SJacopo Mondi 				.height	= 576,
9455113d5b3SJacopo Mondi 			},
9465113d5b3SJacopo Mondi 			.htot		= 1896,
9475113d5b3SJacopo Mondi 			.vblank_def	= 408,
9485113d5b3SJacopo Mondi 		},
9493145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_PAL_720_576,
9503145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_PAL_720_576),
9513145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
9528409d017SJacopo Mondi 	}, {
9538409d017SJacopo Mondi 		/* 1024x768 */
9543145efcdSJacopo Mondi 		.id		= OV5640_MODE_XGA_1024_768,
9553145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
9563145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
9575113d5b3SJacopo Mondi 		.width		= 1024,
9585113d5b3SJacopo Mondi 		.height		= 768,
9595113d5b3SJacopo Mondi 		.dvp_timings = {
9603145efcdSJacopo Mondi 			.analog_crop = {
9613145efcdSJacopo Mondi 				.left	= 0,
9623145efcdSJacopo Mondi 				.top	= 4,
9633145efcdSJacopo Mondi 				.width	= 2624,
9643145efcdSJacopo Mondi 				.height	= 1944,
9653145efcdSJacopo Mondi 			},
9663145efcdSJacopo Mondi 			.crop = {
9673145efcdSJacopo Mondi 				.left	= 16,
9683145efcdSJacopo Mondi 				.top	= 6,
9693145efcdSJacopo Mondi 				.width	= 1024,
9703145efcdSJacopo Mondi 				.height	= 768,
9713145efcdSJacopo Mondi 			},
9723145efcdSJacopo Mondi 			.htot		= 1896,
9733145efcdSJacopo Mondi 			.vblank_def	= 312,
9745113d5b3SJacopo Mondi 		},
9755113d5b3SJacopo Mondi 		.csi2_timings = {
9765113d5b3SJacopo Mondi 			.analog_crop = {
9775113d5b3SJacopo Mondi 				.left	= 0,
9785113d5b3SJacopo Mondi 				.top	= 4,
9795113d5b3SJacopo Mondi 				.width	= OV5640_NATIVE_WIDTH,
9805113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
9815113d5b3SJacopo Mondi 			},
9825113d5b3SJacopo Mondi 			.crop = {
9835113d5b3SJacopo Mondi 				.left	= 16,
9845113d5b3SJacopo Mondi 				.top	= 6,
9855113d5b3SJacopo Mondi 				.width	= 1024,
9865113d5b3SJacopo Mondi 				.height	= 768,
9875113d5b3SJacopo Mondi 			},
9885113d5b3SJacopo Mondi 			.htot		= 1896,
9895113d5b3SJacopo Mondi 			.vblank_def	= 312,
9905113d5b3SJacopo Mondi 		},
9913145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_XGA_1024_768,
9923145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_XGA_1024_768),
9933145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
9948409d017SJacopo Mondi 	}, {
9958409d017SJacopo Mondi 		/* 1280x720 */
9963145efcdSJacopo Mondi 		.id		= OV5640_MODE_720P_1280_720,
9973145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
9983145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_124M,
9995113d5b3SJacopo Mondi 		.width		= 1280,
10005113d5b3SJacopo Mondi 		.height		= 720,
10015113d5b3SJacopo Mondi 		.dvp_timings = {
10023145efcdSJacopo Mondi 			.analog_crop = {
10033145efcdSJacopo Mondi 				.left	= 0,
10043145efcdSJacopo Mondi 				.top	= 250,
10053145efcdSJacopo Mondi 				.width	= 2624,
10063145efcdSJacopo Mondi 				.height	= 1456,
10073145efcdSJacopo Mondi 			},
10083145efcdSJacopo Mondi 			.crop = {
10093145efcdSJacopo Mondi 				.left	= 16,
10103145efcdSJacopo Mondi 				.top	= 4,
10113145efcdSJacopo Mondi 				.width	= 1280,
10123145efcdSJacopo Mondi 				.height	= 720,
10133145efcdSJacopo Mondi 			},
10143145efcdSJacopo Mondi 			.htot		= 1892,
10153145efcdSJacopo Mondi 			.vblank_def	= 20,
10165113d5b3SJacopo Mondi 		},
10175113d5b3SJacopo Mondi 		.csi2_timings = {
10185113d5b3SJacopo Mondi 			.analog_crop = {
10195113d5b3SJacopo Mondi 				.left	= 0,
10205113d5b3SJacopo Mondi 				.top	= 250,
10215113d5b3SJacopo Mondi 				.width	= 2624,
10225113d5b3SJacopo Mondi 				.height	= 1456,
10235113d5b3SJacopo Mondi 			},
10245113d5b3SJacopo Mondi 			.crop = {
10255113d5b3SJacopo Mondi 				.left	= 16,
10265113d5b3SJacopo Mondi 				.top	= 4,
10275113d5b3SJacopo Mondi 				.width	= 1280,
10285113d5b3SJacopo Mondi 				.height	= 720,
10295113d5b3SJacopo Mondi 			},
10305113d5b3SJacopo Mondi 			.htot		= 1892,
10315113d5b3SJacopo Mondi 			.vblank_def	= 20,
10325113d5b3SJacopo Mondi 		},
10333145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_720P_1280_720,
10343145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_720P_1280_720),
10353145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
10368409d017SJacopo Mondi 	}, {
10378409d017SJacopo Mondi 		/* 1920x1080 */
10383145efcdSJacopo Mondi 		.id		= OV5640_MODE_1080P_1920_1080,
10393145efcdSJacopo Mondi 		.dn_mode	= SCALING,
10403145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_148M,
10415113d5b3SJacopo Mondi 		.width		= 1920,
10425113d5b3SJacopo Mondi 		.height		= 1080,
10435113d5b3SJacopo Mondi 		.dvp_timings = {
10443145efcdSJacopo Mondi 			.analog_crop = {
10453145efcdSJacopo Mondi 				.left	= 336,
10463145efcdSJacopo Mondi 				.top	= 434,
10473145efcdSJacopo Mondi 				.width	= 1952,
10483145efcdSJacopo Mondi 				.height	= 1088,
10493145efcdSJacopo Mondi 			},
10503145efcdSJacopo Mondi 			.crop = {
10513145efcdSJacopo Mondi 				.left	= 16,
10523145efcdSJacopo Mondi 				.top	= 4,
10533145efcdSJacopo Mondi 				.width	= 1920,
10543145efcdSJacopo Mondi 				.height	= 1080,
10553145efcdSJacopo Mondi 			},
10563145efcdSJacopo Mondi 			.htot		= 2500,
10573145efcdSJacopo Mondi 			.vblank_def	= 40,
10585113d5b3SJacopo Mondi 		},
10595113d5b3SJacopo Mondi 		.csi2_timings = {
10605113d5b3SJacopo Mondi 			/* Crop the full valid pixel array in the center. */
10615113d5b3SJacopo Mondi 			.analog_crop = {
10625113d5b3SJacopo Mondi 				.left	= 336,
10635113d5b3SJacopo Mondi 				.top	= 434,
10645113d5b3SJacopo Mondi 				.width	= 1952,
10655113d5b3SJacopo Mondi 				.height	= 1088,
10665113d5b3SJacopo Mondi 			},
10675113d5b3SJacopo Mondi 			/* Maintain a larger processing margins. */
10685113d5b3SJacopo Mondi 			.crop = {
10695113d5b3SJacopo Mondi 				.left	= 16,
10705113d5b3SJacopo Mondi 				.top	= 4,
10715113d5b3SJacopo Mondi 				.width	= 1920,
10725113d5b3SJacopo Mondi 				.height	= 1080,
10735113d5b3SJacopo Mondi 			},
10745113d5b3SJacopo Mondi 			.htot		= 2500,
10755113d5b3SJacopo Mondi 			.vblank_def	= 40,
10765113d5b3SJacopo Mondi 		},
10773145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_1080P_1920_1080,
10783145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_1080P_1920_1080),
10793145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
10808409d017SJacopo Mondi 	}, {
10818409d017SJacopo Mondi 		/* 2592x1944 */
10823145efcdSJacopo Mondi 		.id		= OV5640_MODE_QSXGA_2592_1944,
10833145efcdSJacopo Mondi 		.dn_mode	= SCALING,
10843145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_168M,
10855113d5b3SJacopo Mondi 		.width		= OV5640_PIXEL_ARRAY_WIDTH,
10865113d5b3SJacopo Mondi 		.height		= OV5640_PIXEL_ARRAY_HEIGHT,
10875113d5b3SJacopo Mondi 		.dvp_timings = {
10883145efcdSJacopo Mondi 			.analog_crop = {
10893145efcdSJacopo Mondi 				.left	= 0,
10903145efcdSJacopo Mondi 				.top	= 0,
10913145efcdSJacopo Mondi 				.width	= 2624,
10923145efcdSJacopo Mondi 				.height	= 1952,
10933145efcdSJacopo Mondi 			},
10943145efcdSJacopo Mondi 			.crop = {
10953145efcdSJacopo Mondi 				.left	= 16,
10963145efcdSJacopo Mondi 				.top	= 4,
10973145efcdSJacopo Mondi 				.width	= 2592,
10983145efcdSJacopo Mondi 				.height	= 1944,
10993145efcdSJacopo Mondi 			},
11003145efcdSJacopo Mondi 			.htot		= 2844,
11013145efcdSJacopo Mondi 			.vblank_def	= 24,
11025113d5b3SJacopo Mondi 		},
11035113d5b3SJacopo Mondi 		.csi2_timings = {
11045113d5b3SJacopo Mondi 			/* Give more processing margin to full resolution. */
11055113d5b3SJacopo Mondi 			.analog_crop = {
11065113d5b3SJacopo Mondi 				.left	= 0,
11075113d5b3SJacopo Mondi 				.top	= 0,
11085113d5b3SJacopo Mondi 				.width	= OV5640_NATIVE_WIDTH,
11095113d5b3SJacopo Mondi 				.height	= 1952,
11105113d5b3SJacopo Mondi 			},
11115113d5b3SJacopo Mondi 			.crop = {
11125113d5b3SJacopo Mondi 				.left	= 16,
11135113d5b3SJacopo Mondi 				.top	= 4,
11145113d5b3SJacopo Mondi 				.width	= 2592,
11155113d5b3SJacopo Mondi 				.height	= 1944,
11165113d5b3SJacopo Mondi 			},
11175113d5b3SJacopo Mondi 			.htot		= 2844,
11185113d5b3SJacopo Mondi 			.vblank_def	= 24,
11195113d5b3SJacopo Mondi 		},
11203145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_QSXGA_2592_1944,
11213145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_QSXGA_2592_1944),
11223145efcdSJacopo Mondi 		.max_fps	= OV5640_15_FPS
11238409d017SJacopo Mondi 	},
112419a81c14SSteve Longerbeam };
112519a81c14SSteve Longerbeam 
1126*2de6bb97SJacopo Mondi static const struct ov5640_timings *
1127*2de6bb97SJacopo Mondi ov5640_timings(const struct ov5640_dev *sensor,
1128*2de6bb97SJacopo Mondi 	       const struct ov5640_mode_info *mode)
1129*2de6bb97SJacopo Mondi {
1130*2de6bb97SJacopo Mondi 	if (ov5640_is_csi2(sensor))
1131*2de6bb97SJacopo Mondi 		return &mode->csi2_timings;
1132*2de6bb97SJacopo Mondi 
1133*2de6bb97SJacopo Mondi 	return &mode->dvp_timings;
1134*2de6bb97SJacopo Mondi }
1135*2de6bb97SJacopo Mondi 
113619a81c14SSteve Longerbeam static int ov5640_init_slave_id(struct ov5640_dev *sensor)
113719a81c14SSteve Longerbeam {
113819a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
113919a81c14SSteve Longerbeam 	struct i2c_msg msg;
114019a81c14SSteve Longerbeam 	u8 buf[3];
114119a81c14SSteve Longerbeam 	int ret;
114219a81c14SSteve Longerbeam 
114319a81c14SSteve Longerbeam 	if (client->addr == OV5640_DEFAULT_SLAVE_ID)
114419a81c14SSteve Longerbeam 		return 0;
114519a81c14SSteve Longerbeam 
114619a81c14SSteve Longerbeam 	buf[0] = OV5640_REG_SLAVE_ID >> 8;
114719a81c14SSteve Longerbeam 	buf[1] = OV5640_REG_SLAVE_ID & 0xff;
114819a81c14SSteve Longerbeam 	buf[2] = client->addr << 1;
114919a81c14SSteve Longerbeam 
115019a81c14SSteve Longerbeam 	msg.addr = OV5640_DEFAULT_SLAVE_ID;
115119a81c14SSteve Longerbeam 	msg.flags = 0;
115219a81c14SSteve Longerbeam 	msg.buf = buf;
115319a81c14SSteve Longerbeam 	msg.len = sizeof(buf);
115419a81c14SSteve Longerbeam 
115519a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, &msg, 1);
115619a81c14SSteve Longerbeam 	if (ret < 0) {
115719a81c14SSteve Longerbeam 		dev_err(&client->dev, "%s: failed with %d\n", __func__, ret);
115819a81c14SSteve Longerbeam 		return ret;
115919a81c14SSteve Longerbeam 	}
116019a81c14SSteve Longerbeam 
116119a81c14SSteve Longerbeam 	return 0;
116219a81c14SSteve Longerbeam }
116319a81c14SSteve Longerbeam 
116419a81c14SSteve Longerbeam static int ov5640_write_reg(struct ov5640_dev *sensor, u16 reg, u8 val)
116519a81c14SSteve Longerbeam {
116619a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
116719a81c14SSteve Longerbeam 	struct i2c_msg msg;
116819a81c14SSteve Longerbeam 	u8 buf[3];
116919a81c14SSteve Longerbeam 	int ret;
117019a81c14SSteve Longerbeam 
117119a81c14SSteve Longerbeam 	buf[0] = reg >> 8;
117219a81c14SSteve Longerbeam 	buf[1] = reg & 0xff;
117319a81c14SSteve Longerbeam 	buf[2] = val;
117419a81c14SSteve Longerbeam 
117519a81c14SSteve Longerbeam 	msg.addr = client->addr;
117619a81c14SSteve Longerbeam 	msg.flags = client->flags;
117719a81c14SSteve Longerbeam 	msg.buf = buf;
117819a81c14SSteve Longerbeam 	msg.len = sizeof(buf);
117919a81c14SSteve Longerbeam 
118019a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, &msg, 1);
118119a81c14SSteve Longerbeam 	if (ret < 0) {
11823924c623SHugues Fruchet 		dev_err(&client->dev, "%s: error: reg=%x, val=%x\n",
118319a81c14SSteve Longerbeam 			__func__, reg, val);
118419a81c14SSteve Longerbeam 		return ret;
118519a81c14SSteve Longerbeam 	}
118619a81c14SSteve Longerbeam 
118719a81c14SSteve Longerbeam 	return 0;
118819a81c14SSteve Longerbeam }
118919a81c14SSteve Longerbeam 
119019a81c14SSteve Longerbeam static int ov5640_read_reg(struct ov5640_dev *sensor, u16 reg, u8 *val)
119119a81c14SSteve Longerbeam {
119219a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
119319a81c14SSteve Longerbeam 	struct i2c_msg msg[2];
119419a81c14SSteve Longerbeam 	u8 buf[2];
119519a81c14SSteve Longerbeam 	int ret;
119619a81c14SSteve Longerbeam 
119719a81c14SSteve Longerbeam 	buf[0] = reg >> 8;
119819a81c14SSteve Longerbeam 	buf[1] = reg & 0xff;
119919a81c14SSteve Longerbeam 
120019a81c14SSteve Longerbeam 	msg[0].addr = client->addr;
120119a81c14SSteve Longerbeam 	msg[0].flags = client->flags;
120219a81c14SSteve Longerbeam 	msg[0].buf = buf;
120319a81c14SSteve Longerbeam 	msg[0].len = sizeof(buf);
120419a81c14SSteve Longerbeam 
120519a81c14SSteve Longerbeam 	msg[1].addr = client->addr;
120619a81c14SSteve Longerbeam 	msg[1].flags = client->flags | I2C_M_RD;
120719a81c14SSteve Longerbeam 	msg[1].buf = buf;
120819a81c14SSteve Longerbeam 	msg[1].len = 1;
120919a81c14SSteve Longerbeam 
121019a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, msg, 2);
12113924c623SHugues Fruchet 	if (ret < 0) {
12123924c623SHugues Fruchet 		dev_err(&client->dev, "%s: error: reg=%x\n",
12133924c623SHugues Fruchet 			__func__, reg);
121419a81c14SSteve Longerbeam 		return ret;
12153924c623SHugues Fruchet 	}
121619a81c14SSteve Longerbeam 
121719a81c14SSteve Longerbeam 	*val = buf[0];
121819a81c14SSteve Longerbeam 	return 0;
121919a81c14SSteve Longerbeam }
122019a81c14SSteve Longerbeam 
122119a81c14SSteve Longerbeam static int ov5640_read_reg16(struct ov5640_dev *sensor, u16 reg, u16 *val)
122219a81c14SSteve Longerbeam {
122319a81c14SSteve Longerbeam 	u8 hi, lo;
122419a81c14SSteve Longerbeam 	int ret;
122519a81c14SSteve Longerbeam 
122619a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg, &hi);
122719a81c14SSteve Longerbeam 	if (ret)
122819a81c14SSteve Longerbeam 		return ret;
122919a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg + 1, &lo);
123019a81c14SSteve Longerbeam 	if (ret)
123119a81c14SSteve Longerbeam 		return ret;
123219a81c14SSteve Longerbeam 
123319a81c14SSteve Longerbeam 	*val = ((u16)hi << 8) | (u16)lo;
123419a81c14SSteve Longerbeam 	return 0;
123519a81c14SSteve Longerbeam }
123619a81c14SSteve Longerbeam 
123719a81c14SSteve Longerbeam static int ov5640_write_reg16(struct ov5640_dev *sensor, u16 reg, u16 val)
123819a81c14SSteve Longerbeam {
123919a81c14SSteve Longerbeam 	int ret;
124019a81c14SSteve Longerbeam 
124119a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, reg, val >> 8);
124219a81c14SSteve Longerbeam 	if (ret)
124319a81c14SSteve Longerbeam 		return ret;
124419a81c14SSteve Longerbeam 
124519a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, reg + 1, val & 0xff);
124619a81c14SSteve Longerbeam }
124719a81c14SSteve Longerbeam 
124819a81c14SSteve Longerbeam static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg,
124919a81c14SSteve Longerbeam 			  u8 mask, u8 val)
125019a81c14SSteve Longerbeam {
125119a81c14SSteve Longerbeam 	u8 readval;
125219a81c14SSteve Longerbeam 	int ret;
125319a81c14SSteve Longerbeam 
125419a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg, &readval);
125519a81c14SSteve Longerbeam 	if (ret)
125619a81c14SSteve Longerbeam 		return ret;
125719a81c14SSteve Longerbeam 
125819a81c14SSteve Longerbeam 	readval &= ~mask;
125919a81c14SSteve Longerbeam 	val &= mask;
126019a81c14SSteve Longerbeam 	val |= readval;
126119a81c14SSteve Longerbeam 
126219a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, reg, val);
126319a81c14SSteve Longerbeam }
126419a81c14SSteve Longerbeam 
1265aa288248SMaxime Ripard /*
1266aa288248SMaxime Ripard  * After trying the various combinations, reading various
1267f8a7647dSMauro Carvalho Chehab  * documentations spread around the net, and from the various
1268aa288248SMaxime Ripard  * feedback, the clock tree is probably as follows:
1269aa288248SMaxime Ripard  *
1270aa288248SMaxime Ripard  *   +--------------+
1271aa288248SMaxime Ripard  *   |  Ext. Clock  |
1272aa288248SMaxime Ripard  *   +-+------------+
1273aa288248SMaxime Ripard  *     |  +----------+
1274aa288248SMaxime Ripard  *     +->|   PLL1   | - reg 0x3036, for the multiplier
1275aa288248SMaxime Ripard  *        +-+--------+ - reg 0x3037, bits 0-3 for the pre-divider
1276aa288248SMaxime Ripard  *          |  +--------------+
1277aa288248SMaxime Ripard  *          +->| System Clock |  - reg 0x3035, bits 4-7
1278aa288248SMaxime Ripard  *             +-+------------+
1279aa288248SMaxime Ripard  *               |  +--------------+
1280aa288248SMaxime Ripard  *               +->| MIPI Divider | - reg 0x3035, bits 0-3
1281aa288248SMaxime Ripard  *               |  +-+------------+
1282aa288248SMaxime Ripard  *               |    +----------------> MIPI SCLK
1283aa288248SMaxime Ripard  *               |    +  +-----+
1284aa288248SMaxime Ripard  *               |    +->| / 2 |-------> MIPI BIT CLK
1285aa288248SMaxime Ripard  *               |       +-----+
1286aa288248SMaxime Ripard  *               |  +--------------+
1287aa288248SMaxime Ripard  *               +->| PLL Root Div | - reg 0x3037, bit 4
1288aa288248SMaxime Ripard  *                  +-+------------+
1289aa288248SMaxime Ripard  *                    |  +---------+
12904c85f628SPaul Kocialkowski  *                    +->| Bit Div | - reg 0x3034, bits 0-3
1291aa288248SMaxime Ripard  *                       +-+-------+
1292aa288248SMaxime Ripard  *                         |  +-------------+
1293aa288248SMaxime Ripard  *                         +->| SCLK Div    | - reg 0x3108, bits 0-1
1294aa288248SMaxime Ripard  *                         |  +-+-----------+
1295aa288248SMaxime Ripard  *                         |    +---------------> SCLK
1296aa288248SMaxime Ripard  *                         |  +-------------+
1297aa288248SMaxime Ripard  *                         +->| SCLK 2X Div | - reg 0x3108, bits 2-3
1298aa288248SMaxime Ripard  *                         |  +-+-----------+
1299aa288248SMaxime Ripard  *                         |    +---------------> SCLK 2X
1300aa288248SMaxime Ripard  *                         |  +-------------+
1301aa288248SMaxime Ripard  *                         +->| PCLK Div    | - reg 0x3108, bits 4-5
1302aa288248SMaxime Ripard  *                            ++------------+
1303aa288248SMaxime Ripard  *                             +  +-----------+
1304aa288248SMaxime Ripard  *                             +->|   P_DIV   | - reg 0x3035, bits 0-3
1305aa288248SMaxime Ripard  *                                +-----+-----+
1306aa288248SMaxime Ripard  *                                       +------------> PCLK
1307aa288248SMaxime Ripard  *
13086c957ed7SJacopo Mondi  * There seems to be also constraints:
1309aa288248SMaxime Ripard  *  - the PLL pre-divider output rate should be in the 4-27MHz range
1310aa288248SMaxime Ripard  *  - the PLL multiplier output rate should be in the 500-1000MHz range
1311aa288248SMaxime Ripard  *  - PCLK >= SCLK * 2 in YUV, >= SCLK in Raw or JPEG
1312aa288248SMaxime Ripard  */
1313aa288248SMaxime Ripard 
1314aa288248SMaxime Ripard /*
1315aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1316aa288248SMaxime Ripard  * set to 3 in the vendor kernels.
1317aa288248SMaxime Ripard  */
1318aa288248SMaxime Ripard #define OV5640_PLL_PREDIV	3
1319aa288248SMaxime Ripard 
1320aa288248SMaxime Ripard #define OV5640_PLL_MULT_MIN	4
1321aa288248SMaxime Ripard #define OV5640_PLL_MULT_MAX	252
1322aa288248SMaxime Ripard 
1323aa288248SMaxime Ripard /*
1324aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 16, but the value is
1325aa288248SMaxime Ripard  * always set to either 1 or 2 in the vendor kernels.
1326aa288248SMaxime Ripard  */
1327aa288248SMaxime Ripard #define OV5640_SYSDIV_MIN	1
1328aa288248SMaxime Ripard #define OV5640_SYSDIV_MAX	16
1329aa288248SMaxime Ripard 
1330aa288248SMaxime Ripard /*
1331aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 2, but the value is always
1332aa288248SMaxime Ripard  * set to 2 in the vendor kernels.
1333aa288248SMaxime Ripard  */
1334aa288248SMaxime Ripard #define OV5640_PLL_ROOT_DIV			2
1335aa288248SMaxime Ripard #define OV5640_PLL_CTRL3_PLL_ROOT_DIV_2		BIT(4)
1336aa288248SMaxime Ripard 
1337aa288248SMaxime Ripard /*
1338aa288248SMaxime Ripard  * We only supports 8-bit formats at the moment
1339aa288248SMaxime Ripard  */
1340aa288248SMaxime Ripard #define OV5640_BIT_DIV				2
1341aa288248SMaxime Ripard #define OV5640_PLL_CTRL0_MIPI_MODE_8BIT		0x08
1342aa288248SMaxime Ripard 
1343aa288248SMaxime Ripard /*
1344aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1345aa288248SMaxime Ripard  * set to 2 in the vendor kernels.
1346aa288248SMaxime Ripard  */
1347aa288248SMaxime Ripard #define OV5640_SCLK_ROOT_DIV	2
1348aa288248SMaxime Ripard 
1349aa288248SMaxime Ripard /*
1350aa288248SMaxime Ripard  * This is hardcoded so that the consistency is maintained between SCLK and
1351aa288248SMaxime Ripard  * SCLK 2x.
1352aa288248SMaxime Ripard  */
1353aa288248SMaxime Ripard #define OV5640_SCLK2X_ROOT_DIV (OV5640_SCLK_ROOT_DIV / 2)
1354aa288248SMaxime Ripard 
1355aa288248SMaxime Ripard /*
1356aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1357aa288248SMaxime Ripard  * set to 1 in the vendor kernels.
1358aa288248SMaxime Ripard  */
1359aa288248SMaxime Ripard #define OV5640_PCLK_ROOT_DIV			1
1360aa288248SMaxime Ripard #define OV5640_PLL_SYS_ROOT_DIVIDER_BYPASS	0x00
1361aa288248SMaxime Ripard 
1362aa288248SMaxime Ripard static unsigned long ov5640_compute_sys_clk(struct ov5640_dev *sensor,
1363aa288248SMaxime Ripard 					    u8 pll_prediv, u8 pll_mult,
1364aa288248SMaxime Ripard 					    u8 sysdiv)
1365aa288248SMaxime Ripard {
1366aa288248SMaxime Ripard 	unsigned long sysclk = sensor->xclk_freq / pll_prediv * pll_mult;
1367aa288248SMaxime Ripard 
1368aa288248SMaxime Ripard 	/* PLL1 output cannot exceed 1GHz. */
1369aa288248SMaxime Ripard 	if (sysclk / 1000000 > 1000)
1370aa288248SMaxime Ripard 		return 0;
1371aa288248SMaxime Ripard 
1372aa288248SMaxime Ripard 	return sysclk / sysdiv;
1373aa288248SMaxime Ripard }
1374aa288248SMaxime Ripard 
1375aa288248SMaxime Ripard static unsigned long ov5640_calc_sys_clk(struct ov5640_dev *sensor,
1376aa288248SMaxime Ripard 					 unsigned long rate,
1377aa288248SMaxime Ripard 					 u8 *pll_prediv, u8 *pll_mult,
1378aa288248SMaxime Ripard 					 u8 *sysdiv)
1379aa288248SMaxime Ripard {
1380aa288248SMaxime Ripard 	unsigned long best = ~0;
1381aa288248SMaxime Ripard 	u8 best_sysdiv = 1, best_mult = 1;
1382aa288248SMaxime Ripard 	u8 _sysdiv, _pll_mult;
1383aa288248SMaxime Ripard 
1384aa288248SMaxime Ripard 	for (_sysdiv = OV5640_SYSDIV_MIN;
1385aa288248SMaxime Ripard 	     _sysdiv <= OV5640_SYSDIV_MAX;
1386aa288248SMaxime Ripard 	     _sysdiv++) {
1387aa288248SMaxime Ripard 		for (_pll_mult = OV5640_PLL_MULT_MIN;
1388aa288248SMaxime Ripard 		     _pll_mult <= OV5640_PLL_MULT_MAX;
1389aa288248SMaxime Ripard 		     _pll_mult++) {
1390aa288248SMaxime Ripard 			unsigned long _rate;
1391aa288248SMaxime Ripard 
1392aa288248SMaxime Ripard 			/*
1393aa288248SMaxime Ripard 			 * The PLL multiplier cannot be odd if above
1394aa288248SMaxime Ripard 			 * 127.
1395aa288248SMaxime Ripard 			 */
1396aa288248SMaxime Ripard 			if (_pll_mult > 127 && (_pll_mult % 2))
1397aa288248SMaxime Ripard 				continue;
1398aa288248SMaxime Ripard 
1399aa288248SMaxime Ripard 			_rate = ov5640_compute_sys_clk(sensor,
1400aa288248SMaxime Ripard 						       OV5640_PLL_PREDIV,
1401aa288248SMaxime Ripard 						       _pll_mult, _sysdiv);
1402aa288248SMaxime Ripard 
1403aa288248SMaxime Ripard 			/*
1404aa288248SMaxime Ripard 			 * We have reached the maximum allowed PLL1 output,
1405aa288248SMaxime Ripard 			 * increase sysdiv.
1406aa288248SMaxime Ripard 			 */
14072e3df204SAdam Ford 			if (!_rate)
1408aa288248SMaxime Ripard 				break;
1409aa288248SMaxime Ripard 
1410aa288248SMaxime Ripard 			/*
1411aa288248SMaxime Ripard 			 * Prefer rates above the expected clock rate than
1412aa288248SMaxime Ripard 			 * below, even if that means being less precise.
1413aa288248SMaxime Ripard 			 */
1414aa288248SMaxime Ripard 			if (_rate < rate)
1415aa288248SMaxime Ripard 				continue;
1416aa288248SMaxime Ripard 
1417aa288248SMaxime Ripard 			if (abs(rate - _rate) < abs(rate - best)) {
1418aa288248SMaxime Ripard 				best = _rate;
1419aa288248SMaxime Ripard 				best_sysdiv = _sysdiv;
1420aa288248SMaxime Ripard 				best_mult = _pll_mult;
1421aa288248SMaxime Ripard 			}
1422aa288248SMaxime Ripard 
1423aa288248SMaxime Ripard 			if (_rate == rate)
1424aa288248SMaxime Ripard 				goto out;
1425aa288248SMaxime Ripard 		}
1426aa288248SMaxime Ripard 	}
1427aa288248SMaxime Ripard 
1428aa288248SMaxime Ripard out:
1429aa288248SMaxime Ripard 	*sysdiv = best_sysdiv;
1430aa288248SMaxime Ripard 	*pll_prediv = OV5640_PLL_PREDIV;
1431aa288248SMaxime Ripard 	*pll_mult = best_mult;
1432aa288248SMaxime Ripard 
1433aa288248SMaxime Ripard 	return best;
1434aa288248SMaxime Ripard }
1435aa288248SMaxime Ripard 
1436aa288248SMaxime Ripard /*
1437aa288248SMaxime Ripard  * ov5640_set_mipi_pclk() - Calculate the clock tree configuration values
1438aa288248SMaxime Ripard  *			    for the MIPI CSI-2 output.
1439aa288248SMaxime Ripard  */
14406c957ed7SJacopo Mondi static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor)
1441aa288248SMaxime Ripard {
14426c957ed7SJacopo Mondi 	u8 bit_div, mipi_div, pclk_div, sclk_div, sclk2x_div, root_div;
1443aa288248SMaxime Ripard 	u8 prediv, mult, sysdiv;
14446c957ed7SJacopo Mondi 	unsigned long link_freq;
14456c957ed7SJacopo Mondi 	unsigned long sysclk;
14466c957ed7SJacopo Mondi 	u8 pclk_period;
14476c957ed7SJacopo Mondi 	u32 sample_rate;
14486c957ed7SJacopo Mondi 	u32 num_lanes;
1449aa288248SMaxime Ripard 	int ret;
1450aa288248SMaxime Ripard 
14516c957ed7SJacopo Mondi 	/* Use the link freq computed at ov5640_update_pixel_rate() time. */
14526c957ed7SJacopo Mondi 	link_freq = sensor->current_link_freq;
14536c957ed7SJacopo Mondi 
1454aa288248SMaxime Ripard 	/*
14556c957ed7SJacopo Mondi 	 * - mipi_div - Additional divider for the MIPI lane clock.
14566c957ed7SJacopo Mondi 	 *
14576c957ed7SJacopo Mondi 	 * Higher link frequencies would make sysclk > 1GHz.
14586c957ed7SJacopo Mondi 	 * Keep the sysclk low and do not divide in the MIPI domain.
1459aa288248SMaxime Ripard 	 */
14606c957ed7SJacopo Mondi 	if (link_freq > OV5640_LINK_RATE_MAX)
14616c957ed7SJacopo Mondi 		mipi_div = 1;
1462aa288248SMaxime Ripard 	else
14636c957ed7SJacopo Mondi 		mipi_div = 2;
1464aa288248SMaxime Ripard 
14656c957ed7SJacopo Mondi 	sysclk = link_freq * mipi_div;
14666c957ed7SJacopo Mondi 	ov5640_calc_sys_clk(sensor, sysclk, &prediv, &mult, &sysdiv);
1467aa288248SMaxime Ripard 
14686c957ed7SJacopo Mondi 	/*
14696c957ed7SJacopo Mondi 	 * Adjust PLL parameters to maintain the MIPI_SCLK-to-PCLK ratio.
14706c957ed7SJacopo Mondi 	 *
14716c957ed7SJacopo Mondi 	 * - root_div = 2 (fixed)
14726c957ed7SJacopo Mondi 	 * - bit_div : MIPI 8-bit = 2; MIPI 10-bit = 2.5
14736c957ed7SJacopo Mondi 	 * - pclk_div = 1 (fixed)
14746c957ed7SJacopo Mondi 	 * - p_div  = (2 lanes ? mipi_div : 2 * mipi_div)
14756c957ed7SJacopo Mondi 	 *
14766c957ed7SJacopo Mondi 	 * This results in the following MIPI_SCLK depending on the number
14776c957ed7SJacopo Mondi 	 * of lanes:
14786c957ed7SJacopo Mondi 	 *
14796c957ed7SJacopo Mondi 	 * - 2 lanes: MIPI_SCLK = (4 or 5) * PCLK
14806c957ed7SJacopo Mondi 	 * - 1 lanes: MIPI_SCLK = (8 or 10) * PCLK
14816c957ed7SJacopo Mondi 	 */
14826c957ed7SJacopo Mondi 	root_div = OV5640_PLL_CTRL3_PLL_ROOT_DIV_2;
14836c957ed7SJacopo Mondi 	bit_div =  OV5640_PLL_CTRL0_MIPI_MODE_8BIT;
14846c957ed7SJacopo Mondi 	pclk_div = ilog2(OV5640_PCLK_ROOT_DIV);
1485aa288248SMaxime Ripard 
14866c957ed7SJacopo Mondi 	/*
14876c957ed7SJacopo Mondi 	 * Scaler clock:
14886c957ed7SJacopo Mondi 	 * - YUV: PCLK >= 2 * SCLK
14896c957ed7SJacopo Mondi 	 * - RAW or JPEG: PCLK >= SCLK
14906c957ed7SJacopo Mondi 	 * - sclk2x_div = sclk_div / 2
14916c957ed7SJacopo Mondi 	 */
14926c957ed7SJacopo Mondi 	sclk_div = ilog2(OV5640_SCLK_ROOT_DIV);
14936c957ed7SJacopo Mondi 	sclk2x_div = ilog2(OV5640_SCLK2X_ROOT_DIV);
14946c957ed7SJacopo Mondi 
14956c957ed7SJacopo Mondi 	/*
14966c957ed7SJacopo Mondi 	 * Set the pixel clock period expressed in ns with 1-bit decimal
14976c957ed7SJacopo Mondi 	 * (0x01=0.5ns).
14986c957ed7SJacopo Mondi 	 *
14996c957ed7SJacopo Mondi 	 * The register is very briefly documented. In the OV5645 datasheet it
15006c957ed7SJacopo Mondi 	 * is described as (2 * pclk period), and from testing it seems the
15016c957ed7SJacopo Mondi 	 * actual definition is 2 * 8-bit sample period.
15026c957ed7SJacopo Mondi 	 *
15036c957ed7SJacopo Mondi 	 * 2 * sample_period = (mipi_clk * 2 * num_lanes / bpp) * (bpp / 8) / 2
15046c957ed7SJacopo Mondi 	 */
15056c957ed7SJacopo Mondi 	num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes;
15066c957ed7SJacopo Mondi 	sample_rate = (link_freq * mipi_div * num_lanes * 2) / 16;
15076c957ed7SJacopo Mondi 	pclk_period = 2000000000UL / sample_rate;
15086c957ed7SJacopo Mondi 
15096c957ed7SJacopo Mondi 	/* Program the clock tree registers. */
15106c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0, 0x0f, bit_div);
15116c957ed7SJacopo Mondi 	if (ret)
15126c957ed7SJacopo Mondi 		return ret;
15136c957ed7SJacopo Mondi 
15146c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, 0xff,
15156c957ed7SJacopo Mondi 			     (sysdiv << 4) | mipi_div);
1516aa288248SMaxime Ripard 	if (ret)
1517aa288248SMaxime Ripard 		return ret;
1518aa288248SMaxime Ripard 
1519aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2, 0xff, mult);
1520aa288248SMaxime Ripard 	if (ret)
1521aa288248SMaxime Ripard 		return ret;
1522aa288248SMaxime Ripard 
15236c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3, 0x1f,
15246c957ed7SJacopo Mondi 			     root_div | prediv);
1525aa288248SMaxime Ripard 	if (ret)
1526aa288248SMaxime Ripard 		return ret;
1527aa288248SMaxime Ripard 
15286c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
15296c957ed7SJacopo Mondi 			     (pclk_div << 4) | (sclk2x_div << 2) | sclk_div);
15306c957ed7SJacopo Mondi 	if (ret)
15316c957ed7SJacopo Mondi 		return ret;
15326c957ed7SJacopo Mondi 
15336c957ed7SJacopo Mondi 	return ov5640_write_reg(sensor, OV5640_REG_PCLK_PERIOD, pclk_period);
15346c957ed7SJacopo Mondi }
15356c957ed7SJacopo Mondi 
15366c957ed7SJacopo Mondi static u32 ov5640_calc_pixel_rate(struct ov5640_dev *sensor)
15376c957ed7SJacopo Mondi {
15383145efcdSJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
15395113d5b3SJacopo Mondi 	const struct ov5640_timings *timings = &mode->dvp_timings;
15406c957ed7SJacopo Mondi 	u32 rate;
15416c957ed7SJacopo Mondi 
15425113d5b3SJacopo Mondi 	rate = timings->htot * (timings->crop.height + timings->vblank_def);
15436c957ed7SJacopo Mondi 	rate *= ov5640_framerates[sensor->current_fr];
15446c957ed7SJacopo Mondi 
15456c957ed7SJacopo Mondi 	return rate;
1546aa288248SMaxime Ripard }
1547aa288248SMaxime Ripard 
1548aa288248SMaxime Ripard static unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor,
1549aa288248SMaxime Ripard 				      unsigned long rate,
1550aa288248SMaxime Ripard 				      u8 *pll_prediv, u8 *pll_mult, u8 *sysdiv,
1551aa288248SMaxime Ripard 				      u8 *pll_rdiv, u8 *bit_div, u8 *pclk_div)
1552aa288248SMaxime Ripard {
1553aa288248SMaxime Ripard 	unsigned long _rate = rate * OV5640_PLL_ROOT_DIV * OV5640_BIT_DIV *
1554aa288248SMaxime Ripard 				OV5640_PCLK_ROOT_DIV;
1555aa288248SMaxime Ripard 
1556aa288248SMaxime Ripard 	_rate = ov5640_calc_sys_clk(sensor, _rate, pll_prediv, pll_mult,
1557aa288248SMaxime Ripard 				    sysdiv);
1558aa288248SMaxime Ripard 	*pll_rdiv = OV5640_PLL_ROOT_DIV;
1559aa288248SMaxime Ripard 	*bit_div = OV5640_BIT_DIV;
1560aa288248SMaxime Ripard 	*pclk_div = OV5640_PCLK_ROOT_DIV;
1561aa288248SMaxime Ripard 
1562aa288248SMaxime Ripard 	return _rate / *pll_rdiv / *bit_div / *pclk_div;
1563aa288248SMaxime Ripard }
1564aa288248SMaxime Ripard 
15656c957ed7SJacopo Mondi static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor)
1566aa288248SMaxime Ripard {
1567aa288248SMaxime Ripard 	u8 prediv, mult, sysdiv, pll_rdiv, bit_div, pclk_div;
15686c957ed7SJacopo Mondi 	u32 rate;
1569aa288248SMaxime Ripard 	int ret;
1570aa288248SMaxime Ripard 
15716c957ed7SJacopo Mondi 	rate = ov5640_calc_pixel_rate(sensor);
15726c957ed7SJacopo Mondi 	rate *= ov5640_code_to_bpp(sensor->fmt.code);
15736c957ed7SJacopo Mondi 	rate /= sensor->ep.bus.parallel.bus_width;
15746c957ed7SJacopo Mondi 
1575aa288248SMaxime Ripard 	ov5640_calc_pclk(sensor, rate, &prediv, &mult, &sysdiv, &pll_rdiv,
1576aa288248SMaxime Ripard 			 &bit_div, &pclk_div);
1577aa288248SMaxime Ripard 
1578aa288248SMaxime Ripard 	if (bit_div == 2)
1579aa288248SMaxime Ripard 		bit_div = 8;
1580aa288248SMaxime Ripard 
1581aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0,
1582aa288248SMaxime Ripard 			     0x0f, bit_div);
1583aa288248SMaxime Ripard 	if (ret)
1584aa288248SMaxime Ripard 		return ret;
1585aa288248SMaxime Ripard 
1586aa288248SMaxime Ripard 	/*
1587aa288248SMaxime Ripard 	 * We need to set sysdiv according to the clock, and to clear
1588aa288248SMaxime Ripard 	 * the MIPI divider.
1589aa288248SMaxime Ripard 	 */
1590aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1,
1591aa288248SMaxime Ripard 			     0xff, sysdiv << 4);
1592aa288248SMaxime Ripard 	if (ret)
1593aa288248SMaxime Ripard 		return ret;
1594aa288248SMaxime Ripard 
1595aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2,
1596aa288248SMaxime Ripard 			     0xff, mult);
1597aa288248SMaxime Ripard 	if (ret)
1598aa288248SMaxime Ripard 		return ret;
1599aa288248SMaxime Ripard 
1600aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3,
1601aa288248SMaxime Ripard 			     0x1f, prediv | ((pll_rdiv - 1) << 4));
1602aa288248SMaxime Ripard 	if (ret)
1603aa288248SMaxime Ripard 		return ret;
1604aa288248SMaxime Ripard 
1605aa288248SMaxime Ripard 	return ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x30,
1606aa288248SMaxime Ripard 			      (ilog2(pclk_div) << 4));
1607aa288248SMaxime Ripard }
1608aa288248SMaxime Ripard 
16097cb013b1SChen-Yu Tsai /* set JPEG framing sizes */
16107cb013b1SChen-Yu Tsai static int ov5640_set_jpeg_timings(struct ov5640_dev *sensor,
16117cb013b1SChen-Yu Tsai 				   const struct ov5640_mode_info *mode)
16127cb013b1SChen-Yu Tsai {
16137cb013b1SChen-Yu Tsai 	int ret;
16147cb013b1SChen-Yu Tsai 
16152b5c18f9SChen-Yu Tsai 	/*
16162b5c18f9SChen-Yu Tsai 	 * compression mode 3 timing
16172b5c18f9SChen-Yu Tsai 	 *
16182b5c18f9SChen-Yu Tsai 	 * Data is transmitted with programmable width (VFIFO_HSIZE).
16192b5c18f9SChen-Yu Tsai 	 * No padding done. Last line may have less data. Varying
16202b5c18f9SChen-Yu Tsai 	 * number of lines per frame, depending on amount of data.
16212b5c18f9SChen-Yu Tsai 	 */
16222b5c18f9SChen-Yu Tsai 	ret = ov5640_mod_reg(sensor, OV5640_REG_JPG_MODE_SELECT, 0x7, 0x3);
16232b5c18f9SChen-Yu Tsai 	if (ret < 0)
16242b5c18f9SChen-Yu Tsai 		return ret;
16252b5c18f9SChen-Yu Tsai 
16265113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_VFIFO_HSIZE, mode->width);
16277cb013b1SChen-Yu Tsai 	if (ret < 0)
16287cb013b1SChen-Yu Tsai 		return ret;
16297cb013b1SChen-Yu Tsai 
16305113d5b3SJacopo Mondi 	return ov5640_write_reg16(sensor, OV5640_REG_VFIFO_VSIZE, mode->height);
16317cb013b1SChen-Yu Tsai }
16327cb013b1SChen-Yu Tsai 
163319a81c14SSteve Longerbeam /* download ov5640 settings to sensor through i2c */
1634bad1774eSJacopo Mondi static int ov5640_set_timings(struct ov5640_dev *sensor,
1635bad1774eSJacopo Mondi 			      const struct ov5640_mode_info *mode)
1636bad1774eSJacopo Mondi {
16375113d5b3SJacopo Mondi 	const struct ov5640_timings *timings;
16385113d5b3SJacopo Mondi 	const struct v4l2_rect *analog_crop;
16395113d5b3SJacopo Mondi 	const struct v4l2_rect *crop;
1640bad1774eSJacopo Mondi 	int ret;
1641bad1774eSJacopo Mondi 
16427cb013b1SChen-Yu Tsai 	if (sensor->fmt.code == MEDIA_BUS_FMT_JPEG_1X8) {
16437cb013b1SChen-Yu Tsai 		ret = ov5640_set_jpeg_timings(sensor, mode);
16447cb013b1SChen-Yu Tsai 		if (ret < 0)
16457cb013b1SChen-Yu Tsai 			return ret;
16467cb013b1SChen-Yu Tsai 	}
16477cb013b1SChen-Yu Tsai 
1648*2de6bb97SJacopo Mondi 	timings = ov5640_timings(sensor, mode);
16495113d5b3SJacopo Mondi 	analog_crop = &timings->analog_crop;
16505113d5b3SJacopo Mondi 	crop = &timings->crop;
16515113d5b3SJacopo Mondi 
16523145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HS,
16533145efcdSJacopo Mondi 				 analog_crop->left);
1654bad1774eSJacopo Mondi 	if (ret < 0)
1655bad1774eSJacopo Mondi 		return ret;
1656bad1774eSJacopo Mondi 
16573145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VS,
16583145efcdSJacopo Mondi 				 analog_crop->top);
16593145efcdSJacopo Mondi 	if (ret < 0)
16603145efcdSJacopo Mondi 		return ret;
16613145efcdSJacopo Mondi 
16623145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HW,
16633145efcdSJacopo Mondi 				 analog_crop->left + analog_crop->width - 1);
16643145efcdSJacopo Mondi 	if (ret < 0)
16653145efcdSJacopo Mondi 		return ret;
16663145efcdSJacopo Mondi 
16673145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VH,
16683145efcdSJacopo Mondi 				 analog_crop->top + analog_crop->height - 1);
16693145efcdSJacopo Mondi 	if (ret < 0)
16703145efcdSJacopo Mondi 		return ret;
16713145efcdSJacopo Mondi 
16723145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HOFFS, crop->left);
16733145efcdSJacopo Mondi 	if (ret < 0)
16743145efcdSJacopo Mondi 		return ret;
16753145efcdSJacopo Mondi 
16763145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VOFFS, crop->top);
16773145efcdSJacopo Mondi 	if (ret < 0)
16783145efcdSJacopo Mondi 		return ret;
16793145efcdSJacopo Mondi 
16805113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->width);
16813145efcdSJacopo Mondi 	if (ret < 0)
16823145efcdSJacopo Mondi 		return ret;
16833145efcdSJacopo Mondi 
16845113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, mode->height);
1685bad1774eSJacopo Mondi 	if (ret < 0)
1686bad1774eSJacopo Mondi 		return ret;
1687bad1774eSJacopo Mondi 
16885113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, timings->htot);
1689bad1774eSJacopo Mondi 	if (ret < 0)
1690bad1774eSJacopo Mondi 		return ret;
1691bad1774eSJacopo Mondi 
16923145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS,
16935113d5b3SJacopo Mondi 				 mode->height + timings->vblank_def);
16943145efcdSJacopo Mondi 	if (ret < 0)
16953145efcdSJacopo Mondi 		return ret;
16963145efcdSJacopo Mondi 
16973145efcdSJacopo Mondi 	return 0;
1698bad1774eSJacopo Mondi }
1699bad1774eSJacopo Mondi 
170019a81c14SSteve Longerbeam static int ov5640_load_regs(struct ov5640_dev *sensor,
170119a81c14SSteve Longerbeam 			    const struct ov5640_mode_info *mode)
170219a81c14SSteve Longerbeam {
170319a81c14SSteve Longerbeam 	const struct reg_value *regs = mode->reg_data;
170419a81c14SSteve Longerbeam 	unsigned int i;
170519a81c14SSteve Longerbeam 	u32 delay_ms;
170619a81c14SSteve Longerbeam 	u16 reg_addr;
170719a81c14SSteve Longerbeam 	u8 mask, val;
170819a81c14SSteve Longerbeam 	int ret = 0;
170919a81c14SSteve Longerbeam 
171019a81c14SSteve Longerbeam 	for (i = 0; i < mode->reg_data_size; ++i, ++regs) {
171119a81c14SSteve Longerbeam 		delay_ms = regs->delay_ms;
171219a81c14SSteve Longerbeam 		reg_addr = regs->reg_addr;
171319a81c14SSteve Longerbeam 		val = regs->val;
171419a81c14SSteve Longerbeam 		mask = regs->mask;
171519a81c14SSteve Longerbeam 
17163b987d70SLad Prabhakar 		/* remain in power down mode for DVP */
17173b987d70SLad Prabhakar 		if (regs->reg_addr == OV5640_REG_SYS_CTRL0 &&
17183b987d70SLad Prabhakar 		    val == OV5640_REG_SYS_CTRL0_SW_PWUP &&
17198e823f5cSJacopo Mondi 		    !ov5640_is_csi2(sensor))
17203b987d70SLad Prabhakar 			continue;
17213b987d70SLad Prabhakar 
172219a81c14SSteve Longerbeam 		if (mask)
172319a81c14SSteve Longerbeam 			ret = ov5640_mod_reg(sensor, reg_addr, mask, val);
172419a81c14SSteve Longerbeam 		else
172519a81c14SSteve Longerbeam 			ret = ov5640_write_reg(sensor, reg_addr, val);
172619a81c14SSteve Longerbeam 		if (ret)
172719a81c14SSteve Longerbeam 			break;
172819a81c14SSteve Longerbeam 
172919a81c14SSteve Longerbeam 		if (delay_ms)
173019a81c14SSteve Longerbeam 			usleep_range(1000 * delay_ms, 1000 * delay_ms + 100);
173119a81c14SSteve Longerbeam 	}
173219a81c14SSteve Longerbeam 
1733bad1774eSJacopo Mondi 	return ov5640_set_timings(sensor, mode);
173419a81c14SSteve Longerbeam }
173519a81c14SSteve Longerbeam 
1736dc29a1c1SHugues Fruchet static int ov5640_set_autoexposure(struct ov5640_dev *sensor, bool on)
1737dc29a1c1SHugues Fruchet {
1738dc29a1c1SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
1739dc29a1c1SHugues Fruchet 			      BIT(0), on ? 0 : BIT(0));
1740dc29a1c1SHugues Fruchet }
1741dc29a1c1SHugues Fruchet 
174219a81c14SSteve Longerbeam /* read exposure, in number of line periods */
174319a81c14SSteve Longerbeam static int ov5640_get_exposure(struct ov5640_dev *sensor)
174419a81c14SSteve Longerbeam {
174519a81c14SSteve Longerbeam 	int exp, ret;
174619a81c14SSteve Longerbeam 	u8 temp;
174719a81c14SSteve Longerbeam 
174819a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_HI, &temp);
174919a81c14SSteve Longerbeam 	if (ret)
175019a81c14SSteve Longerbeam 		return ret;
175119a81c14SSteve Longerbeam 	exp = ((int)temp & 0x0f) << 16;
175219a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_MED, &temp);
175319a81c14SSteve Longerbeam 	if (ret)
175419a81c14SSteve Longerbeam 		return ret;
175519a81c14SSteve Longerbeam 	exp |= ((int)temp << 8);
175619a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_LO, &temp);
175719a81c14SSteve Longerbeam 	if (ret)
175819a81c14SSteve Longerbeam 		return ret;
175919a81c14SSteve Longerbeam 	exp |= (int)temp;
176019a81c14SSteve Longerbeam 
176119a81c14SSteve Longerbeam 	return exp >> 4;
176219a81c14SSteve Longerbeam }
176319a81c14SSteve Longerbeam 
176419a81c14SSteve Longerbeam /* write exposure, given number of line periods */
176519a81c14SSteve Longerbeam static int ov5640_set_exposure(struct ov5640_dev *sensor, u32 exposure)
176619a81c14SSteve Longerbeam {
176719a81c14SSteve Longerbeam 	int ret;
176819a81c14SSteve Longerbeam 
176919a81c14SSteve Longerbeam 	exposure <<= 4;
177019a81c14SSteve Longerbeam 
177119a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor,
177219a81c14SSteve Longerbeam 			       OV5640_REG_AEC_PK_EXPOSURE_LO,
177319a81c14SSteve Longerbeam 			       exposure & 0xff);
177419a81c14SSteve Longerbeam 	if (ret)
177519a81c14SSteve Longerbeam 		return ret;
177619a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor,
177719a81c14SSteve Longerbeam 			       OV5640_REG_AEC_PK_EXPOSURE_MED,
177819a81c14SSteve Longerbeam 			       (exposure >> 8) & 0xff);
177919a81c14SSteve Longerbeam 	if (ret)
178019a81c14SSteve Longerbeam 		return ret;
178119a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor,
178219a81c14SSteve Longerbeam 				OV5640_REG_AEC_PK_EXPOSURE_HI,
178319a81c14SSteve Longerbeam 				(exposure >> 16) & 0x0f);
178419a81c14SSteve Longerbeam }
178519a81c14SSteve Longerbeam 
178619a81c14SSteve Longerbeam static int ov5640_get_gain(struct ov5640_dev *sensor)
178719a81c14SSteve Longerbeam {
178819a81c14SSteve Longerbeam 	u16 gain;
178919a81c14SSteve Longerbeam 	int ret;
179019a81c14SSteve Longerbeam 
179119a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN, &gain);
179219a81c14SSteve Longerbeam 	if (ret)
179319a81c14SSteve Longerbeam 		return ret;
179419a81c14SSteve Longerbeam 
179519a81c14SSteve Longerbeam 	return gain & 0x3ff;
179619a81c14SSteve Longerbeam }
179719a81c14SSteve Longerbeam 
17983cca8ef5SHugues Fruchet static int ov5640_set_gain(struct ov5640_dev *sensor, int gain)
17993cca8ef5SHugues Fruchet {
18003cca8ef5SHugues Fruchet 	return ov5640_write_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN,
18013cca8ef5SHugues Fruchet 				  (u16)gain & 0x3ff);
18023cca8ef5SHugues Fruchet }
18033cca8ef5SHugues Fruchet 
18043cca8ef5SHugues Fruchet static int ov5640_set_autogain(struct ov5640_dev *sensor, bool on)
18053cca8ef5SHugues Fruchet {
18063cca8ef5SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
18073cca8ef5SHugues Fruchet 			      BIT(1), on ? 0 : BIT(1));
18083cca8ef5SHugues Fruchet }
18093cca8ef5SHugues Fruchet 
1810f22996dbSHugues Fruchet static int ov5640_set_stream_dvp(struct ov5640_dev *sensor, bool on)
1811f22996dbSHugues Fruchet {
18123b987d70SLad Prabhakar 	return ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0, on ?
18133b987d70SLad Prabhakar 				OV5640_REG_SYS_CTRL0_SW_PWUP :
18143b987d70SLad Prabhakar 				OV5640_REG_SYS_CTRL0_SW_PWDN);
1815f22996dbSHugues Fruchet }
1816f22996dbSHugues Fruchet 
1817f22996dbSHugues Fruchet static int ov5640_set_stream_mipi(struct ov5640_dev *sensor, bool on)
181819a81c14SSteve Longerbeam {
181919a81c14SSteve Longerbeam 	int ret;
182019a81c14SSteve Longerbeam 
1821aa4bb8b8SJacopo Mondi 	/*
1822aa4bb8b8SJacopo Mondi 	 * Enable/disable the MIPI interface
1823aa4bb8b8SJacopo Mondi 	 *
1824aa4bb8b8SJacopo Mondi 	 * 0x300e = on ? 0x45 : 0x40
1825aa4bb8b8SJacopo Mondi 	 *
1826aa4bb8b8SJacopo Mondi 	 * FIXME: the sensor manual (version 2.03) reports
1827aa4bb8b8SJacopo Mondi 	 * [7:5] = 000  : 1 data lane mode
1828aa4bb8b8SJacopo Mondi 	 * [7:5] = 001  : 2 data lanes mode
1829aa4bb8b8SJacopo Mondi 	 * But this settings do not work, while the following ones
1830aa4bb8b8SJacopo Mondi 	 * have been validated for 2 data lanes mode.
1831aa4bb8b8SJacopo Mondi 	 *
1832aa4bb8b8SJacopo Mondi 	 * [7:5] = 010	: 2 data lanes mode
1833aa4bb8b8SJacopo Mondi 	 * [4] = 0	: Power up MIPI HS Tx
1834aa4bb8b8SJacopo Mondi 	 * [3] = 0	: Power up MIPI LS Rx
1835aa4bb8b8SJacopo Mondi 	 * [2] = 1/0	: MIPI interface enable/disable
1836aa4bb8b8SJacopo Mondi 	 * [1:0] = 01/00: FIXME: 'debug'
1837aa4bb8b8SJacopo Mondi 	 */
1838aa4bb8b8SJacopo Mondi 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00,
1839aa4bb8b8SJacopo Mondi 			       on ? 0x45 : 0x40);
184019a81c14SSteve Longerbeam 	if (ret)
184119a81c14SSteve Longerbeam 		return ret;
184219a81c14SSteve Longerbeam 
184319a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_FRAME_CTRL01,
184419a81c14SSteve Longerbeam 				on ? 0x00 : 0x0f);
184519a81c14SSteve Longerbeam }
184619a81c14SSteve Longerbeam 
184719a81c14SSteve Longerbeam static int ov5640_get_sysclk(struct ov5640_dev *sensor)
184819a81c14SSteve Longerbeam {
184919a81c14SSteve Longerbeam 	 /* calculate sysclk */
185019a81c14SSteve Longerbeam 	u32 xvclk = sensor->xclk_freq / 10000;
185119a81c14SSteve Longerbeam 	u32 multiplier, prediv, VCO, sysdiv, pll_rdiv;
185219a81c14SSteve Longerbeam 	u32 sclk_rdiv_map[] = {1, 2, 4, 8};
185319a81c14SSteve Longerbeam 	u32 bit_div2x = 1, sclk_rdiv, sysclk;
185419a81c14SSteve Longerbeam 	u8 temp1, temp2;
185519a81c14SSteve Longerbeam 	int ret;
185619a81c14SSteve Longerbeam 
185719a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL0, &temp1);
185819a81c14SSteve Longerbeam 	if (ret)
185919a81c14SSteve Longerbeam 		return ret;
186019a81c14SSteve Longerbeam 	temp2 = temp1 & 0x0f;
186119a81c14SSteve Longerbeam 	if (temp2 == 8 || temp2 == 10)
186219a81c14SSteve Longerbeam 		bit_div2x = temp2 / 2;
186319a81c14SSteve Longerbeam 
186419a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL1, &temp1);
186519a81c14SSteve Longerbeam 	if (ret)
186619a81c14SSteve Longerbeam 		return ret;
186719a81c14SSteve Longerbeam 	sysdiv = temp1 >> 4;
186819a81c14SSteve Longerbeam 	if (sysdiv == 0)
186919a81c14SSteve Longerbeam 		sysdiv = 16;
187019a81c14SSteve Longerbeam 
187119a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL2, &temp1);
187219a81c14SSteve Longerbeam 	if (ret)
187319a81c14SSteve Longerbeam 		return ret;
187419a81c14SSteve Longerbeam 	multiplier = temp1;
187519a81c14SSteve Longerbeam 
187619a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL3, &temp1);
187719a81c14SSteve Longerbeam 	if (ret)
187819a81c14SSteve Longerbeam 		return ret;
187919a81c14SSteve Longerbeam 	prediv = temp1 & 0x0f;
188019a81c14SSteve Longerbeam 	pll_rdiv = ((temp1 >> 4) & 0x01) + 1;
188119a81c14SSteve Longerbeam 
188219a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, &temp1);
188319a81c14SSteve Longerbeam 	if (ret)
188419a81c14SSteve Longerbeam 		return ret;
188519a81c14SSteve Longerbeam 	temp2 = temp1 & 0x03;
188619a81c14SSteve Longerbeam 	sclk_rdiv = sclk_rdiv_map[temp2];
188719a81c14SSteve Longerbeam 
188819a81c14SSteve Longerbeam 	if (!prediv || !sysdiv || !pll_rdiv || !bit_div2x)
188919a81c14SSteve Longerbeam 		return -EINVAL;
189019a81c14SSteve Longerbeam 
189119a81c14SSteve Longerbeam 	VCO = xvclk * multiplier / prediv;
189219a81c14SSteve Longerbeam 
189319a81c14SSteve Longerbeam 	sysclk = VCO / sysdiv / pll_rdiv * 2 / bit_div2x / sclk_rdiv;
189419a81c14SSteve Longerbeam 
189519a81c14SSteve Longerbeam 	return sysclk;
189619a81c14SSteve Longerbeam }
189719a81c14SSteve Longerbeam 
189819a81c14SSteve Longerbeam static int ov5640_set_night_mode(struct ov5640_dev *sensor)
189919a81c14SSteve Longerbeam {
190019a81c14SSteve Longerbeam 	 /* read HTS from register settings */
190119a81c14SSteve Longerbeam 	u8 mode;
190219a81c14SSteve Longerbeam 	int ret;
190319a81c14SSteve Longerbeam 
190419a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_CTRL00, &mode);
190519a81c14SSteve Longerbeam 	if (ret)
190619a81c14SSteve Longerbeam 		return ret;
190719a81c14SSteve Longerbeam 	mode &= 0xfb;
190819a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL00, mode);
190919a81c14SSteve Longerbeam }
191019a81c14SSteve Longerbeam 
191119a81c14SSteve Longerbeam static int ov5640_get_hts(struct ov5640_dev *sensor)
191219a81c14SSteve Longerbeam {
191319a81c14SSteve Longerbeam 	/* read HTS from register settings */
191419a81c14SSteve Longerbeam 	u16 hts;
191519a81c14SSteve Longerbeam 	int ret;
191619a81c14SSteve Longerbeam 
191719a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_HTS, &hts);
191819a81c14SSteve Longerbeam 	if (ret)
191919a81c14SSteve Longerbeam 		return ret;
192019a81c14SSteve Longerbeam 	return hts;
192119a81c14SSteve Longerbeam }
192219a81c14SSteve Longerbeam 
192319a81c14SSteve Longerbeam static int ov5640_get_vts(struct ov5640_dev *sensor)
192419a81c14SSteve Longerbeam {
192519a81c14SSteve Longerbeam 	u16 vts;
192619a81c14SSteve Longerbeam 	int ret;
192719a81c14SSteve Longerbeam 
192819a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_VTS, &vts);
192919a81c14SSteve Longerbeam 	if (ret)
193019a81c14SSteve Longerbeam 		return ret;
193119a81c14SSteve Longerbeam 	return vts;
193219a81c14SSteve Longerbeam }
193319a81c14SSteve Longerbeam 
193419a81c14SSteve Longerbeam static int ov5640_set_vts(struct ov5640_dev *sensor, int vts)
193519a81c14SSteve Longerbeam {
193619a81c14SSteve Longerbeam 	return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, vts);
193719a81c14SSteve Longerbeam }
193819a81c14SSteve Longerbeam 
193919a81c14SSteve Longerbeam static int ov5640_get_light_freq(struct ov5640_dev *sensor)
194019a81c14SSteve Longerbeam {
194119a81c14SSteve Longerbeam 	/* get banding filter value */
194219a81c14SSteve Longerbeam 	int ret, light_freq = 0;
194319a81c14SSteve Longerbeam 	u8 temp, temp1;
194419a81c14SSteve Longerbeam 
194519a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL01, &temp);
194619a81c14SSteve Longerbeam 	if (ret)
194719a81c14SSteve Longerbeam 		return ret;
194819a81c14SSteve Longerbeam 
194919a81c14SSteve Longerbeam 	if (temp & 0x80) {
195019a81c14SSteve Longerbeam 		/* manual */
195119a81c14SSteve Longerbeam 		ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL00,
195219a81c14SSteve Longerbeam 				      &temp1);
195319a81c14SSteve Longerbeam 		if (ret)
195419a81c14SSteve Longerbeam 			return ret;
195519a81c14SSteve Longerbeam 		if (temp1 & 0x04) {
195619a81c14SSteve Longerbeam 			/* 50Hz */
195719a81c14SSteve Longerbeam 			light_freq = 50;
195819a81c14SSteve Longerbeam 		} else {
195919a81c14SSteve Longerbeam 			/* 60Hz */
196019a81c14SSteve Longerbeam 			light_freq = 60;
196119a81c14SSteve Longerbeam 		}
196219a81c14SSteve Longerbeam 	} else {
196319a81c14SSteve Longerbeam 		/* auto */
196419a81c14SSteve Longerbeam 		ret = ov5640_read_reg(sensor, OV5640_REG_SIGMADELTA_CTRL0C,
196519a81c14SSteve Longerbeam 				      &temp1);
196619a81c14SSteve Longerbeam 		if (ret)
196719a81c14SSteve Longerbeam 			return ret;
196819a81c14SSteve Longerbeam 
196919a81c14SSteve Longerbeam 		if (temp1 & 0x01) {
197019a81c14SSteve Longerbeam 			/* 50Hz */
197119a81c14SSteve Longerbeam 			light_freq = 50;
197219a81c14SSteve Longerbeam 		} else {
197319a81c14SSteve Longerbeam 			/* 60Hz */
197419a81c14SSteve Longerbeam 		}
197519a81c14SSteve Longerbeam 	}
197619a81c14SSteve Longerbeam 
197719a81c14SSteve Longerbeam 	return light_freq;
197819a81c14SSteve Longerbeam }
197919a81c14SSteve Longerbeam 
198019a81c14SSteve Longerbeam static int ov5640_set_bandingfilter(struct ov5640_dev *sensor)
198119a81c14SSteve Longerbeam {
198219a81c14SSteve Longerbeam 	u32 band_step60, max_band60, band_step50, max_band50, prev_vts;
198319a81c14SSteve Longerbeam 	int ret;
198419a81c14SSteve Longerbeam 
198519a81c14SSteve Longerbeam 	/* read preview PCLK */
198619a81c14SSteve Longerbeam 	ret = ov5640_get_sysclk(sensor);
198719a81c14SSteve Longerbeam 	if (ret < 0)
198819a81c14SSteve Longerbeam 		return ret;
198919a81c14SSteve Longerbeam 	if (ret == 0)
199019a81c14SSteve Longerbeam 		return -EINVAL;
199119a81c14SSteve Longerbeam 	sensor->prev_sysclk = ret;
199219a81c14SSteve Longerbeam 	/* read preview HTS */
199319a81c14SSteve Longerbeam 	ret = ov5640_get_hts(sensor);
199419a81c14SSteve Longerbeam 	if (ret < 0)
199519a81c14SSteve Longerbeam 		return ret;
199619a81c14SSteve Longerbeam 	if (ret == 0)
199719a81c14SSteve Longerbeam 		return -EINVAL;
199819a81c14SSteve Longerbeam 	sensor->prev_hts = ret;
199919a81c14SSteve Longerbeam 
200019a81c14SSteve Longerbeam 	/* read preview VTS */
200119a81c14SSteve Longerbeam 	ret = ov5640_get_vts(sensor);
200219a81c14SSteve Longerbeam 	if (ret < 0)
200319a81c14SSteve Longerbeam 		return ret;
200419a81c14SSteve Longerbeam 	prev_vts = ret;
200519a81c14SSteve Longerbeam 
200619a81c14SSteve Longerbeam 	/* calculate banding filter */
200719a81c14SSteve Longerbeam 	/* 60Hz */
200819a81c14SSteve Longerbeam 	band_step60 = sensor->prev_sysclk * 100 / sensor->prev_hts * 100 / 120;
200919a81c14SSteve Longerbeam 	ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B60_STEP, band_step60);
201019a81c14SSteve Longerbeam 	if (ret)
201119a81c14SSteve Longerbeam 		return ret;
201219a81c14SSteve Longerbeam 	if (!band_step60)
201319a81c14SSteve Longerbeam 		return -EINVAL;
201419a81c14SSteve Longerbeam 	max_band60 = (int)((prev_vts - 4) / band_step60);
201519a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0D, max_band60);
201619a81c14SSteve Longerbeam 	if (ret)
201719a81c14SSteve Longerbeam 		return ret;
201819a81c14SSteve Longerbeam 
201919a81c14SSteve Longerbeam 	/* 50Hz */
202019a81c14SSteve Longerbeam 	band_step50 = sensor->prev_sysclk * 100 / sensor->prev_hts;
202119a81c14SSteve Longerbeam 	ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B50_STEP, band_step50);
202219a81c14SSteve Longerbeam 	if (ret)
202319a81c14SSteve Longerbeam 		return ret;
202419a81c14SSteve Longerbeam 	if (!band_step50)
202519a81c14SSteve Longerbeam 		return -EINVAL;
202619a81c14SSteve Longerbeam 	max_band50 = (int)((prev_vts - 4) / band_step50);
202719a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0E, max_band50);
202819a81c14SSteve Longerbeam }
202919a81c14SSteve Longerbeam 
203019a81c14SSteve Longerbeam static int ov5640_set_ae_target(struct ov5640_dev *sensor, int target)
203119a81c14SSteve Longerbeam {
203219a81c14SSteve Longerbeam 	/* stable in high */
203319a81c14SSteve Longerbeam 	u32 fast_high, fast_low;
203419a81c14SSteve Longerbeam 	int ret;
203519a81c14SSteve Longerbeam 
203619a81c14SSteve Longerbeam 	sensor->ae_low = target * 23 / 25;	/* 0.92 */
203719a81c14SSteve Longerbeam 	sensor->ae_high = target * 27 / 25;	/* 1.08 */
203819a81c14SSteve Longerbeam 
203919a81c14SSteve Longerbeam 	fast_high = sensor->ae_high << 1;
204019a81c14SSteve Longerbeam 	if (fast_high > 255)
204119a81c14SSteve Longerbeam 		fast_high = 255;
204219a81c14SSteve Longerbeam 
204319a81c14SSteve Longerbeam 	fast_low = sensor->ae_low >> 1;
204419a81c14SSteve Longerbeam 
204519a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0F, sensor->ae_high);
204619a81c14SSteve Longerbeam 	if (ret)
204719a81c14SSteve Longerbeam 		return ret;
204819a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL10, sensor->ae_low);
204919a81c14SSteve Longerbeam 	if (ret)
205019a81c14SSteve Longerbeam 		return ret;
205119a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1B, sensor->ae_high);
205219a81c14SSteve Longerbeam 	if (ret)
205319a81c14SSteve Longerbeam 		return ret;
205419a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1E, sensor->ae_low);
205519a81c14SSteve Longerbeam 	if (ret)
205619a81c14SSteve Longerbeam 		return ret;
205719a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL11, fast_high);
205819a81c14SSteve Longerbeam 	if (ret)
205919a81c14SSteve Longerbeam 		return ret;
206019a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1F, fast_low);
206119a81c14SSteve Longerbeam }
206219a81c14SSteve Longerbeam 
2063c2c3f42dSHugues Fruchet static int ov5640_get_binning(struct ov5640_dev *sensor)
206419a81c14SSteve Longerbeam {
206519a81c14SSteve Longerbeam 	u8 temp;
206619a81c14SSteve Longerbeam 	int ret;
206719a81c14SSteve Longerbeam 
206819a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_TIMING_TC_REG21, &temp);
206919a81c14SSteve Longerbeam 	if (ret)
207019a81c14SSteve Longerbeam 		return ret;
2071c2c3f42dSHugues Fruchet 
2072c2c3f42dSHugues Fruchet 	return temp & BIT(0);
207319a81c14SSteve Longerbeam }
207419a81c14SSteve Longerbeam 
2075ce85705aSHugues Fruchet static int ov5640_set_binning(struct ov5640_dev *sensor, bool enable)
2076ce85705aSHugues Fruchet {
2077ce85705aSHugues Fruchet 	int ret;
2078ce85705aSHugues Fruchet 
2079ce85705aSHugues Fruchet 	/*
2080ce85705aSHugues Fruchet 	 * TIMING TC REG21:
2081ce85705aSHugues Fruchet 	 * - [0]:	Horizontal binning enable
2082ce85705aSHugues Fruchet 	 */
2083ce85705aSHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
2084ce85705aSHugues Fruchet 			     BIT(0), enable ? BIT(0) : 0);
2085ce85705aSHugues Fruchet 	if (ret)
2086ce85705aSHugues Fruchet 		return ret;
2087ce85705aSHugues Fruchet 	/*
2088ce85705aSHugues Fruchet 	 * TIMING TC REG20:
2089ce85705aSHugues Fruchet 	 * - [0]:	Undocumented, but hardcoded init sequences
2090ce85705aSHugues Fruchet 	 *		are always setting REG21/REG20 bit 0 to same value...
2091ce85705aSHugues Fruchet 	 */
2092ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20,
2093ce85705aSHugues Fruchet 			      BIT(0), enable ? BIT(0) : 0);
2094ce85705aSHugues Fruchet }
2095ce85705aSHugues Fruchet 
209619a81c14SSteve Longerbeam static int ov5640_set_virtual_channel(struct ov5640_dev *sensor)
209719a81c14SSteve Longerbeam {
20988670d70aSHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
209919a81c14SSteve Longerbeam 	u8 temp, channel = virtual_channel;
210019a81c14SSteve Longerbeam 	int ret;
210119a81c14SSteve Longerbeam 
21028670d70aSHugues Fruchet 	if (channel > 3) {
21038670d70aSHugues Fruchet 		dev_err(&client->dev,
21048670d70aSHugues Fruchet 			"%s: wrong virtual_channel parameter, expected (0..3), got %d\n",
21058670d70aSHugues Fruchet 			__func__, channel);
210619a81c14SSteve Longerbeam 		return -EINVAL;
21078670d70aSHugues Fruchet 	}
210819a81c14SSteve Longerbeam 
210919a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_DEBUG_MODE, &temp);
211019a81c14SSteve Longerbeam 	if (ret)
211119a81c14SSteve Longerbeam 		return ret;
211219a81c14SSteve Longerbeam 	temp &= ~(3 << 6);
211319a81c14SSteve Longerbeam 	temp |= (channel << 6);
211419a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_DEBUG_MODE, temp);
211519a81c14SSteve Longerbeam }
211619a81c14SSteve Longerbeam 
211719a81c14SSteve Longerbeam static const struct ov5640_mode_info *
211819a81c14SSteve Longerbeam ov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr,
211919a81c14SSteve Longerbeam 		 int width, int height, bool nearest)
212019a81c14SSteve Longerbeam {
21213c4a7372SHugues Fruchet 	const struct ov5640_mode_info *mode;
212219a81c14SSteve Longerbeam 
2123086c25f8SMaxime Ripard 	mode = v4l2_find_nearest_size(ov5640_mode_data,
2124086c25f8SMaxime Ripard 				      ARRAY_SIZE(ov5640_mode_data),
21255113d5b3SJacopo Mondi 				      width, height, width, height);
212619a81c14SSteve Longerbeam 
21273c4a7372SHugues Fruchet 	if (!mode ||
21283145efcdSJacopo Mondi 	    (!nearest &&
21295113d5b3SJacopo Mondi 	     (mode->width != width || mode->height != height)))
21303c4a7372SHugues Fruchet 		return NULL;
213119a81c14SSteve Longerbeam 
21325554c80eSAdam Ford 	/* Check to see if the current mode exceeds the max frame rate */
21335554c80eSAdam Ford 	if (ov5640_framerates[fr] > ov5640_framerates[mode->max_fps])
2134981e4454SBenoit Parrot 		return NULL;
2135981e4454SBenoit Parrot 
213619a81c14SSteve Longerbeam 	return mode;
213719a81c14SSteve Longerbeam }
213819a81c14SSteve Longerbeam 
213919a81c14SSteve Longerbeam /*
214019a81c14SSteve Longerbeam  * sensor changes between scaling and subsampling, go through
214119a81c14SSteve Longerbeam  * exposure calculation
214219a81c14SSteve Longerbeam  */
214341d8d7f5SHugues Fruchet static int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor,
214441d8d7f5SHugues Fruchet 					 const struct ov5640_mode_info *mode)
214519a81c14SSteve Longerbeam {
214619a81c14SSteve Longerbeam 	u32 prev_shutter, prev_gain16;
214719a81c14SSteve Longerbeam 	u32 cap_shutter, cap_gain16;
214819a81c14SSteve Longerbeam 	u32 cap_sysclk, cap_hts, cap_vts;
214919a81c14SSteve Longerbeam 	u32 light_freq, cap_bandfilt, cap_maxband;
215019a81c14SSteve Longerbeam 	u32 cap_gain16_shutter;
215119a81c14SSteve Longerbeam 	u8 average;
215219a81c14SSteve Longerbeam 	int ret;
215319a81c14SSteve Longerbeam 
215441d8d7f5SHugues Fruchet 	if (!mode->reg_data)
215519a81c14SSteve Longerbeam 		return -EINVAL;
215619a81c14SSteve Longerbeam 
215719a81c14SSteve Longerbeam 	/* read preview shutter */
215819a81c14SSteve Longerbeam 	ret = ov5640_get_exposure(sensor);
215919a81c14SSteve Longerbeam 	if (ret < 0)
216019a81c14SSteve Longerbeam 		return ret;
216119a81c14SSteve Longerbeam 	prev_shutter = ret;
2162c2c3f42dSHugues Fruchet 	ret = ov5640_get_binning(sensor);
216319a81c14SSteve Longerbeam 	if (ret < 0)
216419a81c14SSteve Longerbeam 		return ret;
216519a81c14SSteve Longerbeam 	if (ret && mode->id != OV5640_MODE_720P_1280_720 &&
216619a81c14SSteve Longerbeam 	    mode->id != OV5640_MODE_1080P_1920_1080)
216719a81c14SSteve Longerbeam 		prev_shutter *= 2;
216819a81c14SSteve Longerbeam 
216919a81c14SSteve Longerbeam 	/* read preview gain */
217019a81c14SSteve Longerbeam 	ret = ov5640_get_gain(sensor);
217119a81c14SSteve Longerbeam 	if (ret < 0)
217219a81c14SSteve Longerbeam 		return ret;
217319a81c14SSteve Longerbeam 	prev_gain16 = ret;
217419a81c14SSteve Longerbeam 
217519a81c14SSteve Longerbeam 	/* get average */
217619a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AVG_READOUT, &average);
217719a81c14SSteve Longerbeam 	if (ret)
217819a81c14SSteve Longerbeam 		return ret;
217919a81c14SSteve Longerbeam 
218019a81c14SSteve Longerbeam 	/* turn off night mode for capture */
218119a81c14SSteve Longerbeam 	ret = ov5640_set_night_mode(sensor);
218219a81c14SSteve Longerbeam 	if (ret < 0)
218319a81c14SSteve Longerbeam 		return ret;
218419a81c14SSteve Longerbeam 
218519a81c14SSteve Longerbeam 	/* Write capture setting */
218619a81c14SSteve Longerbeam 	ret = ov5640_load_regs(sensor, mode);
218719a81c14SSteve Longerbeam 	if (ret < 0)
218819a81c14SSteve Longerbeam 		return ret;
218919a81c14SSteve Longerbeam 
219019a81c14SSteve Longerbeam 	/* read capture VTS */
219119a81c14SSteve Longerbeam 	ret = ov5640_get_vts(sensor);
219219a81c14SSteve Longerbeam 	if (ret < 0)
219319a81c14SSteve Longerbeam 		return ret;
219419a81c14SSteve Longerbeam 	cap_vts = ret;
219519a81c14SSteve Longerbeam 	ret = ov5640_get_hts(sensor);
219619a81c14SSteve Longerbeam 	if (ret < 0)
219719a81c14SSteve Longerbeam 		return ret;
219819a81c14SSteve Longerbeam 	if (ret == 0)
219919a81c14SSteve Longerbeam 		return -EINVAL;
220019a81c14SSteve Longerbeam 	cap_hts = ret;
220119a81c14SSteve Longerbeam 
220219a81c14SSteve Longerbeam 	ret = ov5640_get_sysclk(sensor);
220319a81c14SSteve Longerbeam 	if (ret < 0)
220419a81c14SSteve Longerbeam 		return ret;
220519a81c14SSteve Longerbeam 	if (ret == 0)
220619a81c14SSteve Longerbeam 		return -EINVAL;
220719a81c14SSteve Longerbeam 	cap_sysclk = ret;
220819a81c14SSteve Longerbeam 
220919a81c14SSteve Longerbeam 	/* calculate capture banding filter */
221019a81c14SSteve Longerbeam 	ret = ov5640_get_light_freq(sensor);
221119a81c14SSteve Longerbeam 	if (ret < 0)
221219a81c14SSteve Longerbeam 		return ret;
221319a81c14SSteve Longerbeam 	light_freq = ret;
221419a81c14SSteve Longerbeam 
221519a81c14SSteve Longerbeam 	if (light_freq == 60) {
221619a81c14SSteve Longerbeam 		/* 60Hz */
221719a81c14SSteve Longerbeam 		cap_bandfilt = cap_sysclk * 100 / cap_hts * 100 / 120;
221819a81c14SSteve Longerbeam 	} else {
221919a81c14SSteve Longerbeam 		/* 50Hz */
222019a81c14SSteve Longerbeam 		cap_bandfilt = cap_sysclk * 100 / cap_hts;
222119a81c14SSteve Longerbeam 	}
222219a81c14SSteve Longerbeam 
222319a81c14SSteve Longerbeam 	if (!sensor->prev_sysclk) {
222419a81c14SSteve Longerbeam 		ret = ov5640_get_sysclk(sensor);
222519a81c14SSteve Longerbeam 		if (ret < 0)
222619a81c14SSteve Longerbeam 			return ret;
222719a81c14SSteve Longerbeam 		if (ret == 0)
222819a81c14SSteve Longerbeam 			return -EINVAL;
222919a81c14SSteve Longerbeam 		sensor->prev_sysclk = ret;
223019a81c14SSteve Longerbeam 	}
223119a81c14SSteve Longerbeam 
223219a81c14SSteve Longerbeam 	if (!cap_bandfilt)
223319a81c14SSteve Longerbeam 		return -EINVAL;
223419a81c14SSteve Longerbeam 
223519a81c14SSteve Longerbeam 	cap_maxband = (int)((cap_vts - 4) / cap_bandfilt);
223619a81c14SSteve Longerbeam 
223719a81c14SSteve Longerbeam 	/* calculate capture shutter/gain16 */
223819a81c14SSteve Longerbeam 	if (average > sensor->ae_low && average < sensor->ae_high) {
223919a81c14SSteve Longerbeam 		/* in stable range */
224019a81c14SSteve Longerbeam 		cap_gain16_shutter =
224119a81c14SSteve Longerbeam 			prev_gain16 * prev_shutter *
224219a81c14SSteve Longerbeam 			cap_sysclk / sensor->prev_sysclk *
224319a81c14SSteve Longerbeam 			sensor->prev_hts / cap_hts *
224419a81c14SSteve Longerbeam 			sensor->ae_target / average;
224519a81c14SSteve Longerbeam 	} else {
224619a81c14SSteve Longerbeam 		cap_gain16_shutter =
224719a81c14SSteve Longerbeam 			prev_gain16 * prev_shutter *
224819a81c14SSteve Longerbeam 			cap_sysclk / sensor->prev_sysclk *
224919a81c14SSteve Longerbeam 			sensor->prev_hts / cap_hts;
225019a81c14SSteve Longerbeam 	}
225119a81c14SSteve Longerbeam 
225219a81c14SSteve Longerbeam 	/* gain to shutter */
225319a81c14SSteve Longerbeam 	if (cap_gain16_shutter < (cap_bandfilt * 16)) {
225419a81c14SSteve Longerbeam 		/* shutter < 1/100 */
225519a81c14SSteve Longerbeam 		cap_shutter = cap_gain16_shutter / 16;
225619a81c14SSteve Longerbeam 		if (cap_shutter < 1)
225719a81c14SSteve Longerbeam 			cap_shutter = 1;
225819a81c14SSteve Longerbeam 
225919a81c14SSteve Longerbeam 		cap_gain16 = cap_gain16_shutter / cap_shutter;
226019a81c14SSteve Longerbeam 		if (cap_gain16 < 16)
226119a81c14SSteve Longerbeam 			cap_gain16 = 16;
226219a81c14SSteve Longerbeam 	} else {
226319a81c14SSteve Longerbeam 		if (cap_gain16_shutter > (cap_bandfilt * cap_maxband * 16)) {
226419a81c14SSteve Longerbeam 			/* exposure reach max */
226519a81c14SSteve Longerbeam 			cap_shutter = cap_bandfilt * cap_maxband;
226619a81c14SSteve Longerbeam 			if (!cap_shutter)
226719a81c14SSteve Longerbeam 				return -EINVAL;
226819a81c14SSteve Longerbeam 
226919a81c14SSteve Longerbeam 			cap_gain16 = cap_gain16_shutter / cap_shutter;
227019a81c14SSteve Longerbeam 		} else {
227119a81c14SSteve Longerbeam 			/* 1/100 < (cap_shutter = n/100) =< max */
227219a81c14SSteve Longerbeam 			cap_shutter =
227319a81c14SSteve Longerbeam 				((int)(cap_gain16_shutter / 16 / cap_bandfilt))
227419a81c14SSteve Longerbeam 				* cap_bandfilt;
227519a81c14SSteve Longerbeam 			if (!cap_shutter)
227619a81c14SSteve Longerbeam 				return -EINVAL;
227719a81c14SSteve Longerbeam 
227819a81c14SSteve Longerbeam 			cap_gain16 = cap_gain16_shutter / cap_shutter;
227919a81c14SSteve Longerbeam 		}
228019a81c14SSteve Longerbeam 	}
228119a81c14SSteve Longerbeam 
228219a81c14SSteve Longerbeam 	/* set capture gain */
22833cca8ef5SHugues Fruchet 	ret = ov5640_set_gain(sensor, cap_gain16);
228419a81c14SSteve Longerbeam 	if (ret)
228519a81c14SSteve Longerbeam 		return ret;
228619a81c14SSteve Longerbeam 
228719a81c14SSteve Longerbeam 	/* write capture shutter */
228819a81c14SSteve Longerbeam 	if (cap_shutter > (cap_vts - 4)) {
228919a81c14SSteve Longerbeam 		cap_vts = cap_shutter + 4;
229019a81c14SSteve Longerbeam 		ret = ov5640_set_vts(sensor, cap_vts);
229119a81c14SSteve Longerbeam 		if (ret < 0)
229219a81c14SSteve Longerbeam 			return ret;
229319a81c14SSteve Longerbeam 	}
229419a81c14SSteve Longerbeam 
229519a81c14SSteve Longerbeam 	/* set exposure */
22963cca8ef5SHugues Fruchet 	return ov5640_set_exposure(sensor, cap_shutter);
229719a81c14SSteve Longerbeam }
229819a81c14SSteve Longerbeam 
229919a81c14SSteve Longerbeam /*
230019a81c14SSteve Longerbeam  * if sensor changes inside scaling or subsampling
230119a81c14SSteve Longerbeam  * change mode directly
230219a81c14SSteve Longerbeam  */
230319a81c14SSteve Longerbeam static int ov5640_set_mode_direct(struct ov5640_dev *sensor,
23043cca8ef5SHugues Fruchet 				  const struct ov5640_mode_info *mode)
230519a81c14SSteve Longerbeam {
230641d8d7f5SHugues Fruchet 	if (!mode->reg_data)
230719a81c14SSteve Longerbeam 		return -EINVAL;
230819a81c14SSteve Longerbeam 
230919a81c14SSteve Longerbeam 	/* Write capture setting */
23103cca8ef5SHugues Fruchet 	return ov5640_load_regs(sensor, mode);
231119a81c14SSteve Longerbeam }
231219a81c14SSteve Longerbeam 
2313985cdcb0SHugues Fruchet static int ov5640_set_mode(struct ov5640_dev *sensor)
231419a81c14SSteve Longerbeam {
231519a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode = sensor->current_mode;
2316985cdcb0SHugues Fruchet 	const struct ov5640_mode_info *orig_mode = sensor->last_mode;
231719a81c14SSteve Longerbeam 	enum ov5640_downsize_mode dn_mode, orig_dn_mode;
23183cca8ef5SHugues Fruchet 	bool auto_gain = sensor->ctrls.auto_gain->val == 1;
2319dc29a1c1SHugues Fruchet 	bool auto_exp =  sensor->ctrls.auto_exp->val == V4L2_EXPOSURE_AUTO;
232019a81c14SSteve Longerbeam 	int ret;
232119a81c14SSteve Longerbeam 
232219a81c14SSteve Longerbeam 	dn_mode = mode->dn_mode;
232319a81c14SSteve Longerbeam 	orig_dn_mode = orig_mode->dn_mode;
232419a81c14SSteve Longerbeam 
232519a81c14SSteve Longerbeam 	/* auto gain and exposure must be turned off when changing modes */
23263cca8ef5SHugues Fruchet 	if (auto_gain) {
23273cca8ef5SHugues Fruchet 		ret = ov5640_set_autogain(sensor, false);
232819a81c14SSteve Longerbeam 		if (ret)
232919a81c14SSteve Longerbeam 			return ret;
23303cca8ef5SHugues Fruchet 	}
2331bf4a4b51SMaxime Ripard 
23323cca8ef5SHugues Fruchet 	if (auto_exp) {
2333dc29a1c1SHugues Fruchet 		ret = ov5640_set_autoexposure(sensor, false);
233419a81c14SSteve Longerbeam 		if (ret)
23353cca8ef5SHugues Fruchet 			goto restore_auto_gain;
23363cca8ef5SHugues Fruchet 	}
233719a81c14SSteve Longerbeam 
23386c957ed7SJacopo Mondi 	if (ov5640_is_csi2(sensor))
23396c957ed7SJacopo Mondi 		ret = ov5640_set_mipi_pclk(sensor);
23406c957ed7SJacopo Mondi 	else
23416c957ed7SJacopo Mondi 		ret = ov5640_set_dvp_pclk(sensor);
2342aa288248SMaxime Ripard 	if (ret < 0)
2343aa288248SMaxime Ripard 		return 0;
2344aa288248SMaxime Ripard 
234519a81c14SSteve Longerbeam 	if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) ||
234619a81c14SSteve Longerbeam 	    (dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) {
234719a81c14SSteve Longerbeam 		/*
234819a81c14SSteve Longerbeam 		 * change between subsampling and scaling
23493cca8ef5SHugues Fruchet 		 * go through exposure calculation
235019a81c14SSteve Longerbeam 		 */
235119a81c14SSteve Longerbeam 		ret = ov5640_set_mode_exposure_calc(sensor, mode);
235219a81c14SSteve Longerbeam 	} else {
235319a81c14SSteve Longerbeam 		/*
235419a81c14SSteve Longerbeam 		 * change inside subsampling or scaling
235519a81c14SSteve Longerbeam 		 * download firmware directly
235619a81c14SSteve Longerbeam 		 */
23573cca8ef5SHugues Fruchet 		ret = ov5640_set_mode_direct(sensor, mode);
235819a81c14SSteve Longerbeam 	}
235919a81c14SSteve Longerbeam 	if (ret < 0)
23603cca8ef5SHugues Fruchet 		goto restore_auto_exp_gain;
23613cca8ef5SHugues Fruchet 
23623cca8ef5SHugues Fruchet 	/* restore auto gain and exposure */
23633cca8ef5SHugues Fruchet 	if (auto_gain)
23643cca8ef5SHugues Fruchet 		ov5640_set_autogain(sensor, true);
23653cca8ef5SHugues Fruchet 	if (auto_exp)
23663cca8ef5SHugues Fruchet 		ov5640_set_autoexposure(sensor, true);
236719a81c14SSteve Longerbeam 
2368ce85705aSHugues Fruchet 	ret = ov5640_set_binning(sensor, dn_mode != SCALING);
2369ce85705aSHugues Fruchet 	if (ret < 0)
2370ce85705aSHugues Fruchet 		return ret;
237119a81c14SSteve Longerbeam 	ret = ov5640_set_ae_target(sensor, sensor->ae_target);
237219a81c14SSteve Longerbeam 	if (ret < 0)
237319a81c14SSteve Longerbeam 		return ret;
237419a81c14SSteve Longerbeam 	ret = ov5640_get_light_freq(sensor);
237519a81c14SSteve Longerbeam 	if (ret < 0)
237619a81c14SSteve Longerbeam 		return ret;
237719a81c14SSteve Longerbeam 	ret = ov5640_set_bandingfilter(sensor);
237819a81c14SSteve Longerbeam 	if (ret < 0)
237919a81c14SSteve Longerbeam 		return ret;
238019a81c14SSteve Longerbeam 	ret = ov5640_set_virtual_channel(sensor);
238119a81c14SSteve Longerbeam 	if (ret < 0)
238219a81c14SSteve Longerbeam 		return ret;
238319a81c14SSteve Longerbeam 
238419a81c14SSteve Longerbeam 	sensor->pending_mode_change = false;
2385985cdcb0SHugues Fruchet 	sensor->last_mode = mode;
238619a81c14SSteve Longerbeam 
238719a81c14SSteve Longerbeam 	return 0;
23883cca8ef5SHugues Fruchet 
23893cca8ef5SHugues Fruchet restore_auto_exp_gain:
23903cca8ef5SHugues Fruchet 	if (auto_exp)
23913cca8ef5SHugues Fruchet 		ov5640_set_autoexposure(sensor, true);
23923cca8ef5SHugues Fruchet restore_auto_gain:
23933cca8ef5SHugues Fruchet 	if (auto_gain)
23943cca8ef5SHugues Fruchet 		ov5640_set_autogain(sensor, true);
23953cca8ef5SHugues Fruchet 
23963cca8ef5SHugues Fruchet 	return ret;
239719a81c14SSteve Longerbeam }
239819a81c14SSteve Longerbeam 
239919ad26f9SAkinobu Mita static int ov5640_set_framefmt(struct ov5640_dev *sensor,
240019ad26f9SAkinobu Mita 			       struct v4l2_mbus_framefmt *format);
240119ad26f9SAkinobu Mita 
240219a81c14SSteve Longerbeam /* restore the last set video mode after chip power-on */
240319a81c14SSteve Longerbeam static int ov5640_restore_mode(struct ov5640_dev *sensor)
240419a81c14SSteve Longerbeam {
240519a81c14SSteve Longerbeam 	int ret;
240619a81c14SSteve Longerbeam 
240719a81c14SSteve Longerbeam 	/* first load the initial register values */
240819a81c14SSteve Longerbeam 	ret = ov5640_load_regs(sensor, &ov5640_mode_init_data);
240919a81c14SSteve Longerbeam 	if (ret < 0)
241019a81c14SSteve Longerbeam 		return ret;
2411985cdcb0SHugues Fruchet 	sensor->last_mode = &ov5640_mode_init_data;
241219a81c14SSteve Longerbeam 
24138f57c2f8SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
24147851fe7aSMaxime Ripard 			     (ilog2(OV5640_SCLK2X_ROOT_DIV) << 2) |
24157851fe7aSMaxime Ripard 			     ilog2(OV5640_SCLK_ROOT_DIV));
24168f57c2f8SMaxime Ripard 	if (ret)
24178f57c2f8SMaxime Ripard 		return ret;
24188f57c2f8SMaxime Ripard 
241919a81c14SSteve Longerbeam 	/* now restore the last capture mode */
2420985cdcb0SHugues Fruchet 	ret = ov5640_set_mode(sensor);
242119ad26f9SAkinobu Mita 	if (ret < 0)
242219ad26f9SAkinobu Mita 		return ret;
242319ad26f9SAkinobu Mita 
242419ad26f9SAkinobu Mita 	return ov5640_set_framefmt(sensor, &sensor->fmt);
242519a81c14SSteve Longerbeam }
242619a81c14SSteve Longerbeam 
242719a81c14SSteve Longerbeam static void ov5640_power(struct ov5640_dev *sensor, bool enable)
242819a81c14SSteve Longerbeam {
24291fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->pwdn_gpio, enable ? 0 : 1);
243019a81c14SSteve Longerbeam }
243119a81c14SSteve Longerbeam 
243219a81c14SSteve Longerbeam static void ov5640_reset(struct ov5640_dev *sensor)
243319a81c14SSteve Longerbeam {
243419a81c14SSteve Longerbeam 	if (!sensor->reset_gpio)
243519a81c14SSteve Longerbeam 		return;
243619a81c14SSteve Longerbeam 
24371fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 0);
243819a81c14SSteve Longerbeam 
243919a81c14SSteve Longerbeam 	/* camera power cycle */
244019a81c14SSteve Longerbeam 	ov5640_power(sensor, false);
244119a81c14SSteve Longerbeam 	usleep_range(5000, 10000);
244219a81c14SSteve Longerbeam 	ov5640_power(sensor, true);
244319a81c14SSteve Longerbeam 	usleep_range(5000, 10000);
244419a81c14SSteve Longerbeam 
24451fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 1);
244619a81c14SSteve Longerbeam 	usleep_range(1000, 2000);
244719a81c14SSteve Longerbeam 
24481fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 0);
24491d4c41f3SLoic Poulain 	usleep_range(20000, 25000);
245019a81c14SSteve Longerbeam }
245119a81c14SSteve Longerbeam 
24520f7acb52SHugues Fruchet static int ov5640_set_power_on(struct ov5640_dev *sensor)
245319a81c14SSteve Longerbeam {
24540f7acb52SHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
24550f7acb52SHugues Fruchet 	int ret;
245619a81c14SSteve Longerbeam 
24570f7acb52SHugues Fruchet 	ret = clk_prepare_enable(sensor->xclk);
24580f7acb52SHugues Fruchet 	if (ret) {
24590f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to enable clock\n",
24600f7acb52SHugues Fruchet 			__func__);
24610f7acb52SHugues Fruchet 		return ret;
24620f7acb52SHugues Fruchet 	}
246319a81c14SSteve Longerbeam 
246419a81c14SSteve Longerbeam 	ret = regulator_bulk_enable(OV5640_NUM_SUPPLIES,
246519a81c14SSteve Longerbeam 				    sensor->supplies);
24660f7acb52SHugues Fruchet 	if (ret) {
24670f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to enable regulators\n",
24680f7acb52SHugues Fruchet 			__func__);
246919a81c14SSteve Longerbeam 		goto xclk_off;
24700f7acb52SHugues Fruchet 	}
247119a81c14SSteve Longerbeam 
247219a81c14SSteve Longerbeam 	ov5640_reset(sensor);
247319a81c14SSteve Longerbeam 	ov5640_power(sensor, true);
247419a81c14SSteve Longerbeam 
247519a81c14SSteve Longerbeam 	ret = ov5640_init_slave_id(sensor);
247619a81c14SSteve Longerbeam 	if (ret)
247719a81c14SSteve Longerbeam 		goto power_off;
247819a81c14SSteve Longerbeam 
24790f7acb52SHugues Fruchet 	return 0;
24800f7acb52SHugues Fruchet 
24810f7acb52SHugues Fruchet power_off:
24820f7acb52SHugues Fruchet 	ov5640_power(sensor, false);
24830f7acb52SHugues Fruchet 	regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies);
24840f7acb52SHugues Fruchet xclk_off:
24850f7acb52SHugues Fruchet 	clk_disable_unprepare(sensor->xclk);
24860f7acb52SHugues Fruchet 	return ret;
24870f7acb52SHugues Fruchet }
24880f7acb52SHugues Fruchet 
24890f7acb52SHugues Fruchet static void ov5640_set_power_off(struct ov5640_dev *sensor)
24900f7acb52SHugues Fruchet {
24910f7acb52SHugues Fruchet 	ov5640_power(sensor, false);
24920f7acb52SHugues Fruchet 	regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies);
24930f7acb52SHugues Fruchet 	clk_disable_unprepare(sensor->xclk);
24940f7acb52SHugues Fruchet }
24950f7acb52SHugues Fruchet 
2496b1751ae6SLad Prabhakar static int ov5640_set_power_mipi(struct ov5640_dev *sensor, bool on)
2497b1751ae6SLad Prabhakar {
2498b1751ae6SLad Prabhakar 	int ret;
2499b1751ae6SLad Prabhakar 
2500b1751ae6SLad Prabhakar 	if (!on) {
2501b1751ae6SLad Prabhakar 		/* Reset MIPI bus settings to their default values. */
2502b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
2503b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x04);
2504b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x00);
2505b1751ae6SLad Prabhakar 		return 0;
2506b1751ae6SLad Prabhakar 	}
2507b1751ae6SLad Prabhakar 
2508b1751ae6SLad Prabhakar 	/*
2509b1751ae6SLad Prabhakar 	 * Power up MIPI HS Tx and LS Rx; 2 data lanes mode
2510b1751ae6SLad Prabhakar 	 *
2511b1751ae6SLad Prabhakar 	 * 0x300e = 0x40
2512b1751ae6SLad Prabhakar 	 * [7:5] = 010	: 2 data lanes mode (see FIXME note in
2513b1751ae6SLad Prabhakar 	 *		  "ov5640_set_stream_mipi()")
2514b1751ae6SLad Prabhakar 	 * [4] = 0	: Power up MIPI HS Tx
2515b1751ae6SLad Prabhakar 	 * [3] = 0	: Power up MIPI LS Rx
2516b1751ae6SLad Prabhakar 	 * [2] = 0	: MIPI interface disabled
2517b1751ae6SLad Prabhakar 	 */
2518b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x40);
2519b1751ae6SLad Prabhakar 	if (ret)
2520b1751ae6SLad Prabhakar 		return ret;
2521b1751ae6SLad Prabhakar 
2522b1751ae6SLad Prabhakar 	/*
2523b1751ae6SLad Prabhakar 	 * Gate clock and set LP11 in 'no packets mode' (idle)
2524b1751ae6SLad Prabhakar 	 *
2525b1751ae6SLad Prabhakar 	 * 0x4800 = 0x24
2526b1751ae6SLad Prabhakar 	 * [5] = 1	: Gate clock when 'no packets'
2527b1751ae6SLad Prabhakar 	 * [2] = 1	: MIPI bus in LP11 when 'no packets'
2528b1751ae6SLad Prabhakar 	 */
2529b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x24);
2530b1751ae6SLad Prabhakar 	if (ret)
2531b1751ae6SLad Prabhakar 		return ret;
2532b1751ae6SLad Prabhakar 
2533b1751ae6SLad Prabhakar 	/*
2534b1751ae6SLad Prabhakar 	 * Set data lanes and clock in LP11 when 'sleeping'
2535b1751ae6SLad Prabhakar 	 *
2536b1751ae6SLad Prabhakar 	 * 0x3019 = 0x70
2537b1751ae6SLad Prabhakar 	 * [6] = 1	: MIPI data lane 2 in LP11 when 'sleeping'
2538b1751ae6SLad Prabhakar 	 * [5] = 1	: MIPI data lane 1 in LP11 when 'sleeping'
2539b1751ae6SLad Prabhakar 	 * [4] = 1	: MIPI clock lane in LP11 when 'sleeping'
2540b1751ae6SLad Prabhakar 	 */
2541b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x70);
2542b1751ae6SLad Prabhakar 	if (ret)
2543b1751ae6SLad Prabhakar 		return ret;
2544b1751ae6SLad Prabhakar 
2545b1751ae6SLad Prabhakar 	/* Give lanes some time to coax into LP11 state. */
2546b1751ae6SLad Prabhakar 	usleep_range(500, 1000);
2547b1751ae6SLad Prabhakar 
2548b1751ae6SLad Prabhakar 	return 0;
2549b1751ae6SLad Prabhakar }
2550b1751ae6SLad Prabhakar 
2551576f5d4bSLad Prabhakar static int ov5640_set_power_dvp(struct ov5640_dev *sensor, bool on)
2552576f5d4bSLad Prabhakar {
2553311a6408SLad Prabhakar 	unsigned int flags = sensor->ep.bus.parallel.flags;
255468579b32SHugues Fruchet 	bool bt656 = sensor->ep.bus_type == V4L2_MBUS_BT656;
255568579b32SHugues Fruchet 	u8 polarities = 0;
2556576f5d4bSLad Prabhakar 	int ret;
2557576f5d4bSLad Prabhakar 
2558576f5d4bSLad Prabhakar 	if (!on) {
2559576f5d4bSLad Prabhakar 		/* Reset settings to their default values. */
256068579b32SHugues Fruchet 		ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00, 0x00);
2561311a6408SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
2562311a6408SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, 0x20);
2563576f5d4bSLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01, 0x00);
2564576f5d4bSLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0x00);
2565576f5d4bSLad Prabhakar 		return 0;
2566576f5d4bSLad Prabhakar 	}
2567576f5d4bSLad Prabhakar 
2568576f5d4bSLad Prabhakar 	/*
2569311a6408SLad Prabhakar 	 * Note about parallel port configuration.
2570311a6408SLad Prabhakar 	 *
2571311a6408SLad Prabhakar 	 * When configured in parallel mode, the OV5640 will
2572311a6408SLad Prabhakar 	 * output 10 bits data on DVP data lines [9:0].
2573311a6408SLad Prabhakar 	 * If only 8 bits data are wanted, the 8 bits data lines
2574311a6408SLad Prabhakar 	 * of the camera interface must be physically connected
2575311a6408SLad Prabhakar 	 * on the DVP data lines [9:2].
2576311a6408SLad Prabhakar 	 *
2577311a6408SLad Prabhakar 	 * Control lines polarity can be configured through
2578311a6408SLad Prabhakar 	 * devicetree endpoint control lines properties.
2579311a6408SLad Prabhakar 	 * If no endpoint control lines properties are set,
2580311a6408SLad Prabhakar 	 * polarity will be as below:
2581311a6408SLad Prabhakar 	 * - VSYNC:	active high
2582311a6408SLad Prabhakar 	 * - HREF:	active low
2583311a6408SLad Prabhakar 	 * - PCLK:	active low
258468579b32SHugues Fruchet 	 *
258568579b32SHugues Fruchet 	 * VSYNC & HREF are not configured if BT656 bus mode is selected
2586311a6408SLad Prabhakar 	 */
258768579b32SHugues Fruchet 
258868579b32SHugues Fruchet 	/*
258968579b32SHugues Fruchet 	 * BT656 embedded synchronization configuration
259068579b32SHugues Fruchet 	 *
259168579b32SHugues Fruchet 	 * CCIR656 CTRL00
259268579b32SHugues Fruchet 	 * - [7]:	SYNC code selection (0: auto generate sync code,
259368579b32SHugues Fruchet 	 *		1: sync code from regs 0x4732-0x4735)
259468579b32SHugues Fruchet 	 * - [6]:	f value in CCIR656 SYNC code when fixed f value
259568579b32SHugues Fruchet 	 * - [5]:	Fixed f value
259668579b32SHugues Fruchet 	 * - [4:3]:	Blank toggle data options (00: data=1'h040/1'h200,
259768579b32SHugues Fruchet 	 *		01: data from regs 0x4736-0x4738, 10: always keep 0)
259868579b32SHugues Fruchet 	 * - [1]:	Clip data disable
259968579b32SHugues Fruchet 	 * - [0]:	CCIR656 mode enable
260068579b32SHugues Fruchet 	 *
260168579b32SHugues Fruchet 	 * Default CCIR656 SAV/EAV mode with default codes
260268579b32SHugues Fruchet 	 * SAV=0xff000080 & EAV=0xff00009d is enabled here with settings:
260368579b32SHugues Fruchet 	 * - CCIR656 mode enable
260468579b32SHugues Fruchet 	 * - auto generation of sync codes
260568579b32SHugues Fruchet 	 * - blank toggle data 1'h040/1'h200
260668579b32SHugues Fruchet 	 * - clip reserved data (0x00 & 0xff changed to 0x01 & 0xfe)
260768579b32SHugues Fruchet 	 */
260868579b32SHugues Fruchet 	ret = ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00,
260968579b32SHugues Fruchet 			       bt656 ? 0x01 : 0x00);
261068579b32SHugues Fruchet 	if (ret)
261168579b32SHugues Fruchet 		return ret;
261268579b32SHugues Fruchet 
2613311a6408SLad Prabhakar 	/*
2614311a6408SLad Prabhakar 	 * configure parallel port control lines polarity
2615311a6408SLad Prabhakar 	 *
2616311a6408SLad Prabhakar 	 * POLARITY CTRL0
2617311a6408SLad Prabhakar 	 * - [5]:	PCLK polarity (0: active low, 1: active high)
2618311a6408SLad Prabhakar 	 * - [1]:	HREF polarity (0: active low, 1: active high)
2619311a6408SLad Prabhakar 	 * - [0]:	VSYNC polarity (mismatch here between
2620311a6408SLad Prabhakar 	 *		datasheet and hardware, 0 is active high
2621311a6408SLad Prabhakar 	 *		and 1 is active low...)
2622311a6408SLad Prabhakar 	 */
262368579b32SHugues Fruchet 	if (!bt656) {
2624311a6408SLad Prabhakar 		if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
262568579b32SHugues Fruchet 			polarities |= BIT(1);
2626311a6408SLad Prabhakar 		if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
262768579b32SHugues Fruchet 			polarities |= BIT(0);
262868579b32SHugues Fruchet 	}
262968579b32SHugues Fruchet 	if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
263068579b32SHugues Fruchet 		polarities |= BIT(5);
2631311a6408SLad Prabhakar 
263268579b32SHugues Fruchet 	ret = ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, polarities);
2633311a6408SLad Prabhakar 	if (ret)
2634311a6408SLad Prabhakar 		return ret;
2635311a6408SLad Prabhakar 
2636311a6408SLad Prabhakar 	/*
263768579b32SHugues Fruchet 	 * powerdown MIPI TX/RX PHY & enable DVP
2638311a6408SLad Prabhakar 	 *
2639311a6408SLad Prabhakar 	 * MIPI CONTROL 00
264068579b32SHugues Fruchet 	 * [4] = 1	: Power down MIPI HS Tx
264168579b32SHugues Fruchet 	 * [3] = 1	: Power down MIPI LS Rx
264268579b32SHugues Fruchet 	 * [2] = 0	: DVP enable (MIPI disable)
2643311a6408SLad Prabhakar 	 */
2644311a6408SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x18);
2645311a6408SLad Prabhakar 	if (ret)
2646311a6408SLad Prabhakar 		return ret;
2647311a6408SLad Prabhakar 
2648311a6408SLad Prabhakar 	/*
2649576f5d4bSLad Prabhakar 	 * enable VSYNC/HREF/PCLK DVP control lines
2650576f5d4bSLad Prabhakar 	 * & D[9:6] DVP data lines
2651576f5d4bSLad Prabhakar 	 *
2652576f5d4bSLad Prabhakar 	 * PAD OUTPUT ENABLE 01
2653576f5d4bSLad Prabhakar 	 * - 6:		VSYNC output enable
2654576f5d4bSLad Prabhakar 	 * - 5:		HREF output enable
2655576f5d4bSLad Prabhakar 	 * - 4:		PCLK output enable
2656576f5d4bSLad Prabhakar 	 * - [3:0]:	D[9:6] output enable
2657576f5d4bSLad Prabhakar 	 */
26584039b037SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01,
265968579b32SHugues Fruchet 			       bt656 ? 0x1f : 0x7f);
2660576f5d4bSLad Prabhakar 	if (ret)
2661576f5d4bSLad Prabhakar 		return ret;
2662576f5d4bSLad Prabhakar 
2663576f5d4bSLad Prabhakar 	/*
2664576f5d4bSLad Prabhakar 	 * enable D[5:0] DVP data lines
2665576f5d4bSLad Prabhakar 	 *
2666576f5d4bSLad Prabhakar 	 * PAD OUTPUT ENABLE 02
2667576f5d4bSLad Prabhakar 	 * - [7:2]:	D[5:0] output enable
2668576f5d4bSLad Prabhakar 	 */
2669576f5d4bSLad Prabhakar 	return ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0xfc);
2670576f5d4bSLad Prabhakar }
2671576f5d4bSLad Prabhakar 
26720f7acb52SHugues Fruchet static int ov5640_set_power(struct ov5640_dev *sensor, bool on)
26730f7acb52SHugues Fruchet {
26740f7acb52SHugues Fruchet 	int ret = 0;
26750f7acb52SHugues Fruchet 
26760f7acb52SHugues Fruchet 	if (on) {
26770f7acb52SHugues Fruchet 		ret = ov5640_set_power_on(sensor);
26780f7acb52SHugues Fruchet 		if (ret)
26790f7acb52SHugues Fruchet 			return ret;
26800f7acb52SHugues Fruchet 
268119a81c14SSteve Longerbeam 		ret = ov5640_restore_mode(sensor);
268219a81c14SSteve Longerbeam 		if (ret)
268319a81c14SSteve Longerbeam 			goto power_off;
2684b1751ae6SLad Prabhakar 	}
268519a81c14SSteve Longerbeam 
2686576f5d4bSLad Prabhakar 	if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY)
2687b1751ae6SLad Prabhakar 		ret = ov5640_set_power_mipi(sensor, on);
2688576f5d4bSLad Prabhakar 	else
2689576f5d4bSLad Prabhakar 		ret = ov5640_set_power_dvp(sensor, on);
2690b1751ae6SLad Prabhakar 	if (ret)
2691b1751ae6SLad Prabhakar 		goto power_off;
2692aa4bb8b8SJacopo Mondi 
2693b1751ae6SLad Prabhakar 	if (!on)
2694aa4bb8b8SJacopo Mondi 		ov5640_set_power_off(sensor);
269519a81c14SSteve Longerbeam 
269619a81c14SSteve Longerbeam 	return 0;
269719a81c14SSteve Longerbeam 
269819a81c14SSteve Longerbeam power_off:
26990f7acb52SHugues Fruchet 	ov5640_set_power_off(sensor);
270019a81c14SSteve Longerbeam 	return ret;
270119a81c14SSteve Longerbeam }
270219a81c14SSteve Longerbeam 
270319a81c14SSteve Longerbeam /* --------------- Subdev Operations --------------- */
270419a81c14SSteve Longerbeam 
270519a81c14SSteve Longerbeam static int ov5640_s_power(struct v4l2_subdev *sd, int on)
270619a81c14SSteve Longerbeam {
270719a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
270819a81c14SSteve Longerbeam 	int ret = 0;
270919a81c14SSteve Longerbeam 
271019a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
271119a81c14SSteve Longerbeam 
271219a81c14SSteve Longerbeam 	/*
271319a81c14SSteve Longerbeam 	 * If the power count is modified from 0 to != 0 or from != 0 to 0,
271419a81c14SSteve Longerbeam 	 * update the power state.
271519a81c14SSteve Longerbeam 	 */
271619a81c14SSteve Longerbeam 	if (sensor->power_count == !on) {
271719a81c14SSteve Longerbeam 		ret = ov5640_set_power(sensor, !!on);
271819a81c14SSteve Longerbeam 		if (ret)
271919a81c14SSteve Longerbeam 			goto out;
272019a81c14SSteve Longerbeam 	}
272119a81c14SSteve Longerbeam 
272219a81c14SSteve Longerbeam 	/* Update the power count. */
272319a81c14SSteve Longerbeam 	sensor->power_count += on ? 1 : -1;
272419a81c14SSteve Longerbeam 	WARN_ON(sensor->power_count < 0);
272519a81c14SSteve Longerbeam out:
272619a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
272719a81c14SSteve Longerbeam 
272819a81c14SSteve Longerbeam 	if (on && !ret && sensor->power_count == 1) {
272919a81c14SSteve Longerbeam 		/* restore controls */
273019a81c14SSteve Longerbeam 		ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
273119a81c14SSteve Longerbeam 	}
273219a81c14SSteve Longerbeam 
273319a81c14SSteve Longerbeam 	return ret;
273419a81c14SSteve Longerbeam }
273519a81c14SSteve Longerbeam 
273619a81c14SSteve Longerbeam static int ov5640_try_frame_interval(struct ov5640_dev *sensor,
273719a81c14SSteve Longerbeam 				     struct v4l2_fract *fi,
273819a81c14SSteve Longerbeam 				     u32 width, u32 height)
273919a81c14SSteve Longerbeam {
274019a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
27416530a5ebSJagan Teki 	enum ov5640_frame_rate rate = OV5640_15_FPS;
2742f6cc192fSMaxime Ripard 	int minfps, maxfps, best_fps, fps;
2743f6cc192fSMaxime Ripard 	int i;
274419a81c14SSteve Longerbeam 
274519a81c14SSteve Longerbeam 	minfps = ov5640_framerates[OV5640_15_FPS];
2746e823fb16SMaxime Ripard 	maxfps = ov5640_framerates[OV5640_60_FPS];
274719a81c14SSteve Longerbeam 
274819a81c14SSteve Longerbeam 	if (fi->numerator == 0) {
274919a81c14SSteve Longerbeam 		fi->denominator = maxfps;
275019a81c14SSteve Longerbeam 		fi->numerator = 1;
2751e823fb16SMaxime Ripard 		rate = OV5640_60_FPS;
2752e823fb16SMaxime Ripard 		goto find_mode;
275319a81c14SSteve Longerbeam 	}
275419a81c14SSteve Longerbeam 
2755f6cc192fSMaxime Ripard 	fps = clamp_val(DIV_ROUND_CLOSEST(fi->denominator, fi->numerator),
2756f6cc192fSMaxime Ripard 			minfps, maxfps);
2757f6cc192fSMaxime Ripard 
2758f6cc192fSMaxime Ripard 	best_fps = minfps;
2759f6cc192fSMaxime Ripard 	for (i = 0; i < ARRAY_SIZE(ov5640_framerates); i++) {
2760f6cc192fSMaxime Ripard 		int curr_fps = ov5640_framerates[i];
2761f6cc192fSMaxime Ripard 
2762f6cc192fSMaxime Ripard 		if (abs(curr_fps - fps) < abs(best_fps - fps)) {
2763f6cc192fSMaxime Ripard 			best_fps = curr_fps;
2764f6cc192fSMaxime Ripard 			rate = i;
2765f6cc192fSMaxime Ripard 		}
2766f6cc192fSMaxime Ripard 	}
276719a81c14SSteve Longerbeam 
276819a81c14SSteve Longerbeam 	fi->numerator = 1;
2769f6cc192fSMaxime Ripard 	fi->denominator = best_fps;
277019a81c14SSteve Longerbeam 
2771e823fb16SMaxime Ripard find_mode:
27725a3ad937SMaxime Ripard 	mode = ov5640_find_mode(sensor, rate, width, height, false);
27735a3ad937SMaxime Ripard 	return mode ? rate : -EINVAL;
277419a81c14SSteve Longerbeam }
277519a81c14SSteve Longerbeam 
277619a81c14SSteve Longerbeam static int ov5640_get_fmt(struct v4l2_subdev *sd,
27770d346d2aSTomi Valkeinen 			  struct v4l2_subdev_state *sd_state,
277819a81c14SSteve Longerbeam 			  struct v4l2_subdev_format *format)
277919a81c14SSteve Longerbeam {
278019a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
278119a81c14SSteve Longerbeam 	struct v4l2_mbus_framefmt *fmt;
278219a81c14SSteve Longerbeam 
278319a81c14SSteve Longerbeam 	if (format->pad != 0)
278419a81c14SSteve Longerbeam 		return -EINVAL;
278519a81c14SSteve Longerbeam 
278619a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
278719a81c14SSteve Longerbeam 
278819a81c14SSteve Longerbeam 	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
27890d346d2aSTomi Valkeinen 		fmt = v4l2_subdev_get_try_format(&sensor->sd, sd_state,
279019a81c14SSteve Longerbeam 						 format->pad);
279119a81c14SSteve Longerbeam 	else
279219a81c14SSteve Longerbeam 		fmt = &sensor->fmt;
279319a81c14SSteve Longerbeam 
279419a81c14SSteve Longerbeam 	format->format = *fmt;
279519a81c14SSteve Longerbeam 
279619a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
279719a81c14SSteve Longerbeam 
279819a81c14SSteve Longerbeam 	return 0;
279919a81c14SSteve Longerbeam }
280019a81c14SSteve Longerbeam 
280119a81c14SSteve Longerbeam static int ov5640_try_fmt_internal(struct v4l2_subdev *sd,
280219a81c14SSteve Longerbeam 				   struct v4l2_mbus_framefmt *fmt,
280319a81c14SSteve Longerbeam 				   enum ov5640_frame_rate fr,
280419a81c14SSteve Longerbeam 				   const struct ov5640_mode_info **new_mode)
280519a81c14SSteve Longerbeam {
280619a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
280719a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
2808e3ee691dSHugues Fruchet 	int i;
280919a81c14SSteve Longerbeam 
281019a81c14SSteve Longerbeam 	mode = ov5640_find_mode(sensor, fr, fmt->width, fmt->height, true);
281119a81c14SSteve Longerbeam 	if (!mode)
281219a81c14SSteve Longerbeam 		return -EINVAL;
28135113d5b3SJacopo Mondi 	fmt->width = mode->width;
28145113d5b3SJacopo Mondi 	fmt->height = mode->height;
281519a81c14SSteve Longerbeam 
281619a81c14SSteve Longerbeam 	if (new_mode)
281719a81c14SSteve Longerbeam 		*new_mode = mode;
2818e3ee691dSHugues Fruchet 
2819e3ee691dSHugues Fruchet 	for (i = 0; i < ARRAY_SIZE(ov5640_formats); i++)
2820e3ee691dSHugues Fruchet 		if (ov5640_formats[i].code == fmt->code)
2821e3ee691dSHugues Fruchet 			break;
2822e3ee691dSHugues Fruchet 	if (i >= ARRAY_SIZE(ov5640_formats))
2823e6441fdeSHugues Fruchet 		i = 0;
2824e6441fdeSHugues Fruchet 
2825e6441fdeSHugues Fruchet 	fmt->code = ov5640_formats[i].code;
2826e6441fdeSHugues Fruchet 	fmt->colorspace = ov5640_formats[i].colorspace;
2827e6441fdeSHugues Fruchet 	fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
2828e6441fdeSHugues Fruchet 	fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
2829e6441fdeSHugues Fruchet 	fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
2830e3ee691dSHugues Fruchet 
283119a81c14SSteve Longerbeam 	return 0;
283219a81c14SSteve Longerbeam }
283319a81c14SSteve Longerbeam 
28343c28588fSJacopo Mondi static int ov5640_update_pixel_rate(struct ov5640_dev *sensor)
28353c28588fSJacopo Mondi {
28363c28588fSJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
28373c28588fSJacopo Mondi 	enum ov5640_pixel_rate_id pixel_rate_id = mode->pixel_rate;
28383c28588fSJacopo Mondi 	struct v4l2_mbus_framefmt *fmt = &sensor->fmt;
28393c28588fSJacopo Mondi 	unsigned int i = 0;
28403c28588fSJacopo Mondi 	u32 pixel_rate;
28413c28588fSJacopo Mondi 	s64 link_freq;
28423c28588fSJacopo Mondi 	u32 num_lanes;
28433c28588fSJacopo Mondi 	u32 bpp;
28443c28588fSJacopo Mondi 
28453c28588fSJacopo Mondi 	/*
28463c28588fSJacopo Mondi 	 * Update the pixel rate control value.
28473c28588fSJacopo Mondi 	 *
28483c28588fSJacopo Mondi 	 * For DVP mode, maintain the pixel rate calculation using fixed FPS.
28493c28588fSJacopo Mondi 	 */
28503c28588fSJacopo Mondi 	if (!ov5640_is_csi2(sensor)) {
28513c28588fSJacopo Mondi 		__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate,
28523c28588fSJacopo Mondi 					 ov5640_calc_pixel_rate(sensor));
28533c28588fSJacopo Mondi 
28543c28588fSJacopo Mondi 		return 0;
28553c28588fSJacopo Mondi 	}
28563c28588fSJacopo Mondi 
28573c28588fSJacopo Mondi 	/*
28583c28588fSJacopo Mondi 	 * The MIPI CSI-2 link frequency should comply with the CSI-2
28593c28588fSJacopo Mondi 	 * specification and be lower than 1GHz.
28603c28588fSJacopo Mondi 	 *
28613c28588fSJacopo Mondi 	 * Start from the suggested pixel_rate for the current mode and
28623c28588fSJacopo Mondi 	 * progressively slow it down if it exceeds 1GHz.
28633c28588fSJacopo Mondi 	 */
28643c28588fSJacopo Mondi 	num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes;
28653c28588fSJacopo Mondi 	bpp = ov5640_code_to_bpp(fmt->code);
28663c28588fSJacopo Mondi 	do {
28673c28588fSJacopo Mondi 		pixel_rate = ov5640_pixel_rates[pixel_rate_id];
28683c28588fSJacopo Mondi 		link_freq = pixel_rate * bpp / (2 * num_lanes);
28693c28588fSJacopo Mondi 	} while (link_freq >= 1000000000U &&
28703c28588fSJacopo Mondi 		 ++pixel_rate_id < OV5640_NUM_PIXEL_RATES);
28713c28588fSJacopo Mondi 
28723c28588fSJacopo Mondi 	sensor->current_link_freq = link_freq;
28733c28588fSJacopo Mondi 
28743c28588fSJacopo Mondi 	/*
28753c28588fSJacopo Mondi 	 * Higher link rates require the clock tree to be programmed with
28763c28588fSJacopo Mondi 	 * 'mipi_div' = 1; this has the effect of halving the actual output
28773c28588fSJacopo Mondi 	 * pixel rate in the MIPI domain.
28783c28588fSJacopo Mondi 	 *
28793c28588fSJacopo Mondi 	 * Adjust the pixel rate and link frequency control value to report it
28803c28588fSJacopo Mondi 	 * correctly to userspace.
28813c28588fSJacopo Mondi 	 */
28823c28588fSJacopo Mondi 	if (link_freq > OV5640_LINK_RATE_MAX) {
28833c28588fSJacopo Mondi 		pixel_rate /= 2;
28843c28588fSJacopo Mondi 		link_freq /= 2;
28853c28588fSJacopo Mondi 	}
28863c28588fSJacopo Mondi 
28873c28588fSJacopo Mondi 	for (i = 0; i < ARRAY_SIZE(ov5640_csi2_link_freqs); ++i) {
28883c28588fSJacopo Mondi 		if (ov5640_csi2_link_freqs[i] == link_freq)
28893c28588fSJacopo Mondi 			break;
28903c28588fSJacopo Mondi 	}
28913c28588fSJacopo Mondi 	WARN_ON(i == ARRAY_SIZE(ov5640_csi2_link_freqs));
28923c28588fSJacopo Mondi 
28933c28588fSJacopo Mondi 	__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, pixel_rate);
28943c28588fSJacopo Mondi 	__v4l2_ctrl_s_ctrl(sensor->ctrls.link_freq, i);
28953c28588fSJacopo Mondi 
28963c28588fSJacopo Mondi 	return 0;
28973c28588fSJacopo Mondi }
28983c28588fSJacopo Mondi 
289919a81c14SSteve Longerbeam static int ov5640_set_fmt(struct v4l2_subdev *sd,
29000d346d2aSTomi Valkeinen 			  struct v4l2_subdev_state *sd_state,
290119a81c14SSteve Longerbeam 			  struct v4l2_subdev_format *format)
290219a81c14SSteve Longerbeam {
290319a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
290419a81c14SSteve Longerbeam 	const struct ov5640_mode_info *new_mode;
2905e6441fdeSHugues Fruchet 	struct v4l2_mbus_framefmt *mbus_fmt = &format->format;
290619a81c14SSteve Longerbeam 	int ret;
290719a81c14SSteve Longerbeam 
290819a81c14SSteve Longerbeam 	if (format->pad != 0)
290919a81c14SSteve Longerbeam 		return -EINVAL;
291019a81c14SSteve Longerbeam 
291119a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
291219a81c14SSteve Longerbeam 
291319a81c14SSteve Longerbeam 	if (sensor->streaming) {
291419a81c14SSteve Longerbeam 		ret = -EBUSY;
291519a81c14SSteve Longerbeam 		goto out;
291619a81c14SSteve Longerbeam 	}
291719a81c14SSteve Longerbeam 
2918e6441fdeSHugues Fruchet 	ret = ov5640_try_fmt_internal(sd, mbus_fmt,
291919a81c14SSteve Longerbeam 				      sensor->current_fr, &new_mode);
292019a81c14SSteve Longerbeam 	if (ret)
292119a81c14SSteve Longerbeam 		goto out;
292219a81c14SSteve Longerbeam 
2923e738f5ddSMirela Rabulea 	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
2924e738f5ddSMirela Rabulea 		*v4l2_subdev_get_try_format(sd, sd_state, 0) = *mbus_fmt;
2925e738f5ddSMirela Rabulea 		goto out;
2926e738f5ddSMirela Rabulea 	}
292719a81c14SSteve Longerbeam 
29286949d864SHugues Fruchet 	if (new_mode != sensor->current_mode) {
292919a81c14SSteve Longerbeam 		sensor->current_mode = new_mode;
293019a81c14SSteve Longerbeam 		sensor->pending_mode_change = true;
29316949d864SHugues Fruchet 	}
293207115449SJacopo Mondi 	if (mbus_fmt->code != sensor->fmt.code)
2933fb98e29fSHugues Fruchet 		sensor->pending_fmt_change = true;
293407115449SJacopo Mondi 
2935e738f5ddSMirela Rabulea 	/* update format even if code is unchanged, resolution might change */
2936e738f5ddSMirela Rabulea 	sensor->fmt = *mbus_fmt;
2937e738f5ddSMirela Rabulea 
29383c28588fSJacopo Mondi 	ov5640_update_pixel_rate(sensor);
29393c28588fSJacopo Mondi 
294019a81c14SSteve Longerbeam out:
294119a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
294219a81c14SSteve Longerbeam 	return ret;
294319a81c14SSteve Longerbeam }
294419a81c14SSteve Longerbeam 
2945e3ee691dSHugues Fruchet static int ov5640_set_framefmt(struct ov5640_dev *sensor,
2946e3ee691dSHugues Fruchet 			       struct v4l2_mbus_framefmt *format)
2947e3ee691dSHugues Fruchet {
2948e3ee691dSHugues Fruchet 	int ret = 0;
2949d47c4126SHugues Fruchet 	bool is_jpeg = false;
2950b7ed3abdSLoic Poulain 	u8 fmt, mux;
2951e3ee691dSHugues Fruchet 
2952e3ee691dSHugues Fruchet 	switch (format->code) {
29531536fbdbSXavier Roumegue 	case MEDIA_BUS_FMT_UYVY8_1X16:
2954e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_UYVY8_2X8:
2955e3ee691dSHugues Fruchet 		/* YUV422, UYVY */
2956b7ed3abdSLoic Poulain 		fmt = 0x3f;
2957b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_YUV422;
2958e3ee691dSHugues Fruchet 		break;
29591536fbdbSXavier Roumegue 	case MEDIA_BUS_FMT_YUYV8_1X16:
2960e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_YUYV8_2X8:
2961e3ee691dSHugues Fruchet 		/* YUV422, YUYV */
2962b7ed3abdSLoic Poulain 		fmt = 0x30;
2963b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_YUV422;
2964e3ee691dSHugues Fruchet 		break;
2965e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_RGB565_2X8_LE:
2966e3ee691dSHugues Fruchet 		/* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */
2967b7ed3abdSLoic Poulain 		fmt = 0x6F;
2968b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RGB;
2969e3ee691dSHugues Fruchet 		break;
2970e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_RGB565_2X8_BE:
2971e3ee691dSHugues Fruchet 		/* RGB565 {r[4:0],g[5:3]},{g[2:0],b[4:0]} */
2972b7ed3abdSLoic Poulain 		fmt = 0x61;
2973b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RGB;
2974e3ee691dSHugues Fruchet 		break;
2975d47c4126SHugues Fruchet 	case MEDIA_BUS_FMT_JPEG_1X8:
2976d47c4126SHugues Fruchet 		/* YUV422, YUYV */
2977b7ed3abdSLoic Poulain 		fmt = 0x30;
2978b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_YUV422;
2979d47c4126SHugues Fruchet 		is_jpeg = true;
2980d47c4126SHugues Fruchet 		break;
2981b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SBGGR8_1X8:
2982b7ed3abdSLoic Poulain 		/* Raw, BGBG... / GRGR... */
2983b7ed3abdSLoic Poulain 		fmt = 0x00;
2984b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2985b7ed3abdSLoic Poulain 		break;
2986b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SGBRG8_1X8:
2987b7ed3abdSLoic Poulain 		/* Raw bayer, GBGB... / RGRG... */
2988b7ed3abdSLoic Poulain 		fmt = 0x01;
2989b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2990b7ed3abdSLoic Poulain 		break;
2991b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SGRBG8_1X8:
2992b7ed3abdSLoic Poulain 		/* Raw bayer, GRGR... / BGBG... */
2993b7ed3abdSLoic Poulain 		fmt = 0x02;
2994b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2995b7ed3abdSLoic Poulain 		break;
2996b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SRGGB8_1X8:
2997b7ed3abdSLoic Poulain 		/* Raw bayer, RGRG... / GBGB... */
2998b7ed3abdSLoic Poulain 		fmt = 0x03;
2999b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
3000b7ed3abdSLoic Poulain 		break;
3001e3ee691dSHugues Fruchet 	default:
3002e3ee691dSHugues Fruchet 		return -EINVAL;
3003e3ee691dSHugues Fruchet 	}
3004e3ee691dSHugues Fruchet 
3005e3ee691dSHugues Fruchet 	/* FORMAT CONTROL00: YUV and RGB formatting */
3006b7ed3abdSLoic Poulain 	ret = ov5640_write_reg(sensor, OV5640_REG_FORMAT_CONTROL00, fmt);
3007e3ee691dSHugues Fruchet 	if (ret)
3008e3ee691dSHugues Fruchet 		return ret;
3009e3ee691dSHugues Fruchet 
3010e3ee691dSHugues Fruchet 	/* FORMAT MUX CONTROL: ISP YUV or RGB */
3011b7ed3abdSLoic Poulain 	ret = ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL, mux);
3012d47c4126SHugues Fruchet 	if (ret)
3013d47c4126SHugues Fruchet 		return ret;
3014d47c4126SHugues Fruchet 
3015d47c4126SHugues Fruchet 	/*
3016d47c4126SHugues Fruchet 	 * TIMING TC REG21:
3017d47c4126SHugues Fruchet 	 * - [5]:	JPEG enable
3018d47c4126SHugues Fruchet 	 */
3019d47c4126SHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
3020d47c4126SHugues Fruchet 			     BIT(5), is_jpeg ? BIT(5) : 0);
3021d47c4126SHugues Fruchet 	if (ret)
3022d47c4126SHugues Fruchet 		return ret;
3023d47c4126SHugues Fruchet 
3024d47c4126SHugues Fruchet 	/*
3025d47c4126SHugues Fruchet 	 * SYSTEM RESET02:
3026d47c4126SHugues Fruchet 	 * - [4]:	Reset JFIFO
3027d47c4126SHugues Fruchet 	 * - [3]:	Reset SFIFO
3028d47c4126SHugues Fruchet 	 * - [2]:	Reset JPEG
3029d47c4126SHugues Fruchet 	 */
3030d47c4126SHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_RESET02,
3031d47c4126SHugues Fruchet 			     BIT(4) | BIT(3) | BIT(2),
3032d47c4126SHugues Fruchet 			     is_jpeg ? 0 : (BIT(4) | BIT(3) | BIT(2)));
3033d47c4126SHugues Fruchet 	if (ret)
3034d47c4126SHugues Fruchet 		return ret;
3035d47c4126SHugues Fruchet 
3036d47c4126SHugues Fruchet 	/*
3037d47c4126SHugues Fruchet 	 * CLOCK ENABLE02:
3038d47c4126SHugues Fruchet 	 * - [5]:	Enable JPEG 2x clock
3039d47c4126SHugues Fruchet 	 * - [3]:	Enable JPEG clock
3040d47c4126SHugues Fruchet 	 */
3041d47c4126SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_SYS_CLOCK_ENABLE02,
3042d47c4126SHugues Fruchet 			      BIT(5) | BIT(3),
3043d47c4126SHugues Fruchet 			      is_jpeg ? (BIT(5) | BIT(3)) : 0);
3044e3ee691dSHugues Fruchet }
304519a81c14SSteve Longerbeam 
304619a81c14SSteve Longerbeam /*
304719a81c14SSteve Longerbeam  * Sensor Controls.
304819a81c14SSteve Longerbeam  */
304919a81c14SSteve Longerbeam 
305019a81c14SSteve Longerbeam static int ov5640_set_ctrl_hue(struct ov5640_dev *sensor, int value)
305119a81c14SSteve Longerbeam {
305219a81c14SSteve Longerbeam 	int ret;
305319a81c14SSteve Longerbeam 
305419a81c14SSteve Longerbeam 	if (value) {
305519a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
305619a81c14SSteve Longerbeam 				     BIT(0), BIT(0));
305719a81c14SSteve Longerbeam 		if (ret)
305819a81c14SSteve Longerbeam 			return ret;
305919a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_SDE_CTRL1, value);
306019a81c14SSteve Longerbeam 	} else {
306119a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(0), 0);
306219a81c14SSteve Longerbeam 	}
306319a81c14SSteve Longerbeam 
306419a81c14SSteve Longerbeam 	return ret;
306519a81c14SSteve Longerbeam }
306619a81c14SSteve Longerbeam 
306719a81c14SSteve Longerbeam static int ov5640_set_ctrl_contrast(struct ov5640_dev *sensor, int value)
306819a81c14SSteve Longerbeam {
306919a81c14SSteve Longerbeam 	int ret;
307019a81c14SSteve Longerbeam 
307119a81c14SSteve Longerbeam 	if (value) {
307219a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
307319a81c14SSteve Longerbeam 				     BIT(2), BIT(2));
307419a81c14SSteve Longerbeam 		if (ret)
307519a81c14SSteve Longerbeam 			return ret;
307619a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL5,
307719a81c14SSteve Longerbeam 				       value & 0xff);
307819a81c14SSteve Longerbeam 	} else {
307919a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(2), 0);
308019a81c14SSteve Longerbeam 	}
308119a81c14SSteve Longerbeam 
308219a81c14SSteve Longerbeam 	return ret;
308319a81c14SSteve Longerbeam }
308419a81c14SSteve Longerbeam 
308519a81c14SSteve Longerbeam static int ov5640_set_ctrl_saturation(struct ov5640_dev *sensor, int value)
308619a81c14SSteve Longerbeam {
308719a81c14SSteve Longerbeam 	int ret;
308819a81c14SSteve Longerbeam 
308919a81c14SSteve Longerbeam 	if (value) {
309019a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
309119a81c14SSteve Longerbeam 				     BIT(1), BIT(1));
309219a81c14SSteve Longerbeam 		if (ret)
309319a81c14SSteve Longerbeam 			return ret;
309419a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL3,
309519a81c14SSteve Longerbeam 				       value & 0xff);
309619a81c14SSteve Longerbeam 		if (ret)
309719a81c14SSteve Longerbeam 			return ret;
309819a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL4,
309919a81c14SSteve Longerbeam 				       value & 0xff);
310019a81c14SSteve Longerbeam 	} else {
310119a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(1), 0);
310219a81c14SSteve Longerbeam 	}
310319a81c14SSteve Longerbeam 
310419a81c14SSteve Longerbeam 	return ret;
310519a81c14SSteve Longerbeam }
310619a81c14SSteve Longerbeam 
310719a81c14SSteve Longerbeam static int ov5640_set_ctrl_white_balance(struct ov5640_dev *sensor, int awb)
310819a81c14SSteve Longerbeam {
310919a81c14SSteve Longerbeam 	int ret;
311019a81c14SSteve Longerbeam 
311119a81c14SSteve Longerbeam 	ret = ov5640_mod_reg(sensor, OV5640_REG_AWB_MANUAL_CTRL,
311219a81c14SSteve Longerbeam 			     BIT(0), awb ? 0 : 1);
311319a81c14SSteve Longerbeam 	if (ret)
311419a81c14SSteve Longerbeam 		return ret;
311519a81c14SSteve Longerbeam 
311619a81c14SSteve Longerbeam 	if (!awb) {
311719a81c14SSteve Longerbeam 		u16 red = (u16)sensor->ctrls.red_balance->val;
311819a81c14SSteve Longerbeam 		u16 blue = (u16)sensor->ctrls.blue_balance->val;
311919a81c14SSteve Longerbeam 
312019a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_R_GAIN, red);
312119a81c14SSteve Longerbeam 		if (ret)
312219a81c14SSteve Longerbeam 			return ret;
312319a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_B_GAIN, blue);
312419a81c14SSteve Longerbeam 	}
312519a81c14SSteve Longerbeam 
312619a81c14SSteve Longerbeam 	return ret;
312719a81c14SSteve Longerbeam }
312819a81c14SSteve Longerbeam 
31293cca8ef5SHugues Fruchet static int ov5640_set_ctrl_exposure(struct ov5640_dev *sensor,
31303cca8ef5SHugues Fruchet 				    enum v4l2_exposure_auto_type auto_exposure)
313119a81c14SSteve Longerbeam {
313219a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
31333cca8ef5SHugues Fruchet 	bool auto_exp = (auto_exposure == V4L2_EXPOSURE_AUTO);
313419a81c14SSteve Longerbeam 	int ret = 0;
313519a81c14SSteve Longerbeam 
313619a81c14SSteve Longerbeam 	if (ctrls->auto_exp->is_new) {
31373cca8ef5SHugues Fruchet 		ret = ov5640_set_autoexposure(sensor, auto_exp);
313819a81c14SSteve Longerbeam 		if (ret)
313919a81c14SSteve Longerbeam 			return ret;
314019a81c14SSteve Longerbeam 	}
314119a81c14SSteve Longerbeam 
31423cca8ef5SHugues Fruchet 	if (!auto_exp && ctrls->exposure->is_new) {
314319a81c14SSteve Longerbeam 		u16 max_exp;
314419a81c14SSteve Longerbeam 
314519a81c14SSteve Longerbeam 		ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_VTS,
314619a81c14SSteve Longerbeam 					&max_exp);
314719a81c14SSteve Longerbeam 		if (ret)
314819a81c14SSteve Longerbeam 			return ret;
314919a81c14SSteve Longerbeam 		ret = ov5640_get_vts(sensor);
315019a81c14SSteve Longerbeam 		if (ret < 0)
315119a81c14SSteve Longerbeam 			return ret;
315219a81c14SSteve Longerbeam 		max_exp += ret;
31536146fde3SHugues Fruchet 		ret = 0;
315419a81c14SSteve Longerbeam 
315519a81c14SSteve Longerbeam 		if (ctrls->exposure->val < max_exp)
315619a81c14SSteve Longerbeam 			ret = ov5640_set_exposure(sensor, ctrls->exposure->val);
315719a81c14SSteve Longerbeam 	}
315819a81c14SSteve Longerbeam 
315919a81c14SSteve Longerbeam 	return ret;
316019a81c14SSteve Longerbeam }
316119a81c14SSteve Longerbeam 
31623cca8ef5SHugues Fruchet static int ov5640_set_ctrl_gain(struct ov5640_dev *sensor, bool auto_gain)
316319a81c14SSteve Longerbeam {
316419a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
316519a81c14SSteve Longerbeam 	int ret = 0;
316619a81c14SSteve Longerbeam 
316719a81c14SSteve Longerbeam 	if (ctrls->auto_gain->is_new) {
31683cca8ef5SHugues Fruchet 		ret = ov5640_set_autogain(sensor, auto_gain);
316919a81c14SSteve Longerbeam 		if (ret)
317019a81c14SSteve Longerbeam 			return ret;
317119a81c14SSteve Longerbeam 	}
317219a81c14SSteve Longerbeam 
31733cca8ef5SHugues Fruchet 	if (!auto_gain && ctrls->gain->is_new)
31743cca8ef5SHugues Fruchet 		ret = ov5640_set_gain(sensor, ctrls->gain->val);
317519a81c14SSteve Longerbeam 
317619a81c14SSteve Longerbeam 	return ret;
317719a81c14SSteve Longerbeam }
317819a81c14SSteve Longerbeam 
31799f6d7bacSChen-Yu Tsai static const char * const test_pattern_menu[] = {
31809f6d7bacSChen-Yu Tsai 	"Disabled",
31819f6d7bacSChen-Yu Tsai 	"Color bars",
3182bddc5cdfSChen-Yu Tsai 	"Color bars w/ rolling bar",
3183bddc5cdfSChen-Yu Tsai 	"Color squares",
3184bddc5cdfSChen-Yu Tsai 	"Color squares w/ rolling bar",
31859f6d7bacSChen-Yu Tsai };
31869f6d7bacSChen-Yu Tsai 
3187a0c29afbSChen-Yu Tsai #define OV5640_TEST_ENABLE		BIT(7)
3188a0c29afbSChen-Yu Tsai #define OV5640_TEST_ROLLING		BIT(6)	/* rolling horizontal bar */
3189a0c29afbSChen-Yu Tsai #define OV5640_TEST_TRANSPARENT		BIT(5)
3190a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE_BW		BIT(4)	/* black & white squares */
3191a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_STANDARD	(0 << 2)
3192a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_1	(1 << 2)
3193a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_HOR_CHANGE	(2 << 2)
3194a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_2	(3 << 2)
3195a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR			(0 << 0)
3196a0c29afbSChen-Yu Tsai #define OV5640_TEST_RANDOM		(1 << 0)
3197a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE		(2 << 0)
3198a0c29afbSChen-Yu Tsai #define OV5640_TEST_BLACK		(3 << 0)
3199a0c29afbSChen-Yu Tsai 
3200a0c29afbSChen-Yu Tsai static const u8 test_pattern_val[] = {
3201a0c29afbSChen-Yu Tsai 	0,
32022aff1fc3SChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_BAR_VERT_CHANGE_1 |
3203a0c29afbSChen-Yu Tsai 		OV5640_TEST_BAR,
3204bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_ROLLING |
3205bddc5cdfSChen-Yu Tsai 		OV5640_TEST_BAR_VERT_CHANGE_1 | OV5640_TEST_BAR,
3206bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_SQUARE,
3207bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_ROLLING | OV5640_TEST_SQUARE,
3208a0c29afbSChen-Yu Tsai };
3209a0c29afbSChen-Yu Tsai 
321019a81c14SSteve Longerbeam static int ov5640_set_ctrl_test_pattern(struct ov5640_dev *sensor, int value)
321119a81c14SSteve Longerbeam {
3212a0c29afbSChen-Yu Tsai 	return ov5640_write_reg(sensor, OV5640_REG_PRE_ISP_TEST_SET1,
3213a0c29afbSChen-Yu Tsai 				test_pattern_val[value]);
321419a81c14SSteve Longerbeam }
321519a81c14SSteve Longerbeam 
32161068fecaSMylène Josserand static int ov5640_set_ctrl_light_freq(struct ov5640_dev *sensor, int value)
32171068fecaSMylène Josserand {
32181068fecaSMylène Josserand 	int ret;
32191068fecaSMylène Josserand 
32201068fecaSMylène Josserand 	ret = ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL01, BIT(7),
32211068fecaSMylène Josserand 			     (value == V4L2_CID_POWER_LINE_FREQUENCY_AUTO) ?
32221068fecaSMylène Josserand 			     0 : BIT(7));
32231068fecaSMylène Josserand 	if (ret)
32241068fecaSMylène Josserand 		return ret;
32251068fecaSMylène Josserand 
32261068fecaSMylène Josserand 	return ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL00, BIT(2),
32271068fecaSMylène Josserand 			      (value == V4L2_CID_POWER_LINE_FREQUENCY_50HZ) ?
32281068fecaSMylène Josserand 			      BIT(2) : 0);
32291068fecaSMylène Josserand }
32301068fecaSMylène Josserand 
3231ce85705aSHugues Fruchet static int ov5640_set_ctrl_hflip(struct ov5640_dev *sensor, int value)
3232ce85705aSHugues Fruchet {
3233ce85705aSHugues Fruchet 	/*
3234c3f3ba3eSHugues Fruchet 	 * If sensor is mounted upside down, mirror logic is inversed.
3235c3f3ba3eSHugues Fruchet 	 *
3236ce85705aSHugues Fruchet 	 * Sensor is a BSI (Back Side Illuminated) one,
3237ce85705aSHugues Fruchet 	 * so image captured is physically mirrored.
3238ce85705aSHugues Fruchet 	 * This is why mirror logic is inversed in
3239ce85705aSHugues Fruchet 	 * order to cancel this mirror effect.
3240ce85705aSHugues Fruchet 	 */
3241ce85705aSHugues Fruchet 
3242ce85705aSHugues Fruchet 	/*
3243ce85705aSHugues Fruchet 	 * TIMING TC REG21:
3244ce85705aSHugues Fruchet 	 * - [2]:	ISP mirror
3245ce85705aSHugues Fruchet 	 * - [1]:	Sensor mirror
3246ce85705aSHugues Fruchet 	 */
3247ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
3248ce85705aSHugues Fruchet 			      BIT(2) | BIT(1),
3249c3f3ba3eSHugues Fruchet 			      (!(value ^ sensor->upside_down)) ?
3250c3f3ba3eSHugues Fruchet 			      (BIT(2) | BIT(1)) : 0);
3251ce85705aSHugues Fruchet }
3252ce85705aSHugues Fruchet 
3253ce85705aSHugues Fruchet static int ov5640_set_ctrl_vflip(struct ov5640_dev *sensor, int value)
3254ce85705aSHugues Fruchet {
3255c3f3ba3eSHugues Fruchet 	/* If sensor is mounted upside down, flip logic is inversed */
3256c3f3ba3eSHugues Fruchet 
3257ce85705aSHugues Fruchet 	/*
3258ce85705aSHugues Fruchet 	 * TIMING TC REG20:
3259ce85705aSHugues Fruchet 	 * - [2]:	ISP vflip
3260ce85705aSHugues Fruchet 	 * - [1]:	Sensor vflip
3261ce85705aSHugues Fruchet 	 */
3262ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20,
3263ce85705aSHugues Fruchet 			      BIT(2) | BIT(1),
3264c3f3ba3eSHugues Fruchet 			      (value ^ sensor->upside_down) ?
3265c3f3ba3eSHugues Fruchet 			      (BIT(2) | BIT(1)) : 0);
3266ce85705aSHugues Fruchet }
3267ce85705aSHugues Fruchet 
326819a81c14SSteve Longerbeam static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
326919a81c14SSteve Longerbeam {
327019a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
327119a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
327219a81c14SSteve Longerbeam 	int val;
327319a81c14SSteve Longerbeam 
327419a81c14SSteve Longerbeam 	/* v4l2_ctrl_lock() locks our own mutex */
327519a81c14SSteve Longerbeam 
327619a81c14SSteve Longerbeam 	switch (ctrl->id) {
327719a81c14SSteve Longerbeam 	case V4L2_CID_AUTOGAIN:
327819a81c14SSteve Longerbeam 		val = ov5640_get_gain(sensor);
327919a81c14SSteve Longerbeam 		if (val < 0)
328019a81c14SSteve Longerbeam 			return val;
328119a81c14SSteve Longerbeam 		sensor->ctrls.gain->val = val;
328219a81c14SSteve Longerbeam 		break;
328319a81c14SSteve Longerbeam 	case V4L2_CID_EXPOSURE_AUTO:
328419a81c14SSteve Longerbeam 		val = ov5640_get_exposure(sensor);
328519a81c14SSteve Longerbeam 		if (val < 0)
328619a81c14SSteve Longerbeam 			return val;
328719a81c14SSteve Longerbeam 		sensor->ctrls.exposure->val = val;
328819a81c14SSteve Longerbeam 		break;
328919a81c14SSteve Longerbeam 	}
329019a81c14SSteve Longerbeam 
329119a81c14SSteve Longerbeam 	return 0;
329219a81c14SSteve Longerbeam }
329319a81c14SSteve Longerbeam 
329419a81c14SSteve Longerbeam static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl)
329519a81c14SSteve Longerbeam {
329619a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
329719a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
329819a81c14SSteve Longerbeam 	int ret;
329919a81c14SSteve Longerbeam 
330019a81c14SSteve Longerbeam 	/* v4l2_ctrl_lock() locks our own mutex */
330119a81c14SSteve Longerbeam 
330219a81c14SSteve Longerbeam 	/*
330319a81c14SSteve Longerbeam 	 * If the device is not powered up by the host driver do
330419a81c14SSteve Longerbeam 	 * not apply any controls to H/W at this time. Instead
330519a81c14SSteve Longerbeam 	 * the controls will be restored right after power-up.
330619a81c14SSteve Longerbeam 	 */
330719a81c14SSteve Longerbeam 	if (sensor->power_count == 0)
330819a81c14SSteve Longerbeam 		return 0;
330919a81c14SSteve Longerbeam 
331019a81c14SSteve Longerbeam 	switch (ctrl->id) {
331119a81c14SSteve Longerbeam 	case V4L2_CID_AUTOGAIN:
331219a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_gain(sensor, ctrl->val);
331319a81c14SSteve Longerbeam 		break;
331419a81c14SSteve Longerbeam 	case V4L2_CID_EXPOSURE_AUTO:
331519a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_exposure(sensor, ctrl->val);
331619a81c14SSteve Longerbeam 		break;
331719a81c14SSteve Longerbeam 	case V4L2_CID_AUTO_WHITE_BALANCE:
331819a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_white_balance(sensor, ctrl->val);
331919a81c14SSteve Longerbeam 		break;
332019a81c14SSteve Longerbeam 	case V4L2_CID_HUE:
332119a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_hue(sensor, ctrl->val);
332219a81c14SSteve Longerbeam 		break;
332319a81c14SSteve Longerbeam 	case V4L2_CID_CONTRAST:
332419a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_contrast(sensor, ctrl->val);
332519a81c14SSteve Longerbeam 		break;
332619a81c14SSteve Longerbeam 	case V4L2_CID_SATURATION:
332719a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_saturation(sensor, ctrl->val);
332819a81c14SSteve Longerbeam 		break;
332919a81c14SSteve Longerbeam 	case V4L2_CID_TEST_PATTERN:
333019a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_test_pattern(sensor, ctrl->val);
333119a81c14SSteve Longerbeam 		break;
33321068fecaSMylène Josserand 	case V4L2_CID_POWER_LINE_FREQUENCY:
33331068fecaSMylène Josserand 		ret = ov5640_set_ctrl_light_freq(sensor, ctrl->val);
33341068fecaSMylène Josserand 		break;
3335ce85705aSHugues Fruchet 	case V4L2_CID_HFLIP:
3336ce85705aSHugues Fruchet 		ret = ov5640_set_ctrl_hflip(sensor, ctrl->val);
3337ce85705aSHugues Fruchet 		break;
3338ce85705aSHugues Fruchet 	case V4L2_CID_VFLIP:
3339ce85705aSHugues Fruchet 		ret = ov5640_set_ctrl_vflip(sensor, ctrl->val);
3340ce85705aSHugues Fruchet 		break;
334119a81c14SSteve Longerbeam 	default:
334219a81c14SSteve Longerbeam 		ret = -EINVAL;
334319a81c14SSteve Longerbeam 		break;
334419a81c14SSteve Longerbeam 	}
334519a81c14SSteve Longerbeam 
334619a81c14SSteve Longerbeam 	return ret;
334719a81c14SSteve Longerbeam }
334819a81c14SSteve Longerbeam 
334919a81c14SSteve Longerbeam static const struct v4l2_ctrl_ops ov5640_ctrl_ops = {
335019a81c14SSteve Longerbeam 	.g_volatile_ctrl = ov5640_g_volatile_ctrl,
335119a81c14SSteve Longerbeam 	.s_ctrl = ov5640_s_ctrl,
335219a81c14SSteve Longerbeam };
335319a81c14SSteve Longerbeam 
335419a81c14SSteve Longerbeam static int ov5640_init_controls(struct ov5640_dev *sensor)
335519a81c14SSteve Longerbeam {
335622845bf2SJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
335719a81c14SSteve Longerbeam 	const struct v4l2_ctrl_ops *ops = &ov5640_ctrl_ops;
335819a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
335919a81c14SSteve Longerbeam 	struct v4l2_ctrl_handler *hdl = &ctrls->handler;
336019a81c14SSteve Longerbeam 	int ret;
336119a81c14SSteve Longerbeam 
336219a81c14SSteve Longerbeam 	v4l2_ctrl_handler_init(hdl, 32);
336319a81c14SSteve Longerbeam 
336419a81c14SSteve Longerbeam 	/* we can use our own mutex for the ctrl lock */
336519a81c14SSteve Longerbeam 	hdl->lock = &sensor->lock;
336619a81c14SSteve Longerbeam 
3367cc196e48SBenoit Parrot 	/* Clock related controls */
3368cc196e48SBenoit Parrot 	ctrls->pixel_rate = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE,
336922845bf2SJacopo Mondi 			      ov5640_pixel_rates[OV5640_NUM_PIXEL_RATES - 1],
337022845bf2SJacopo Mondi 			      ov5640_pixel_rates[0], 1,
337122845bf2SJacopo Mondi 			      ov5640_pixel_rates[mode->pixel_rate]);
3372cc196e48SBenoit Parrot 
33737a3b8d4bSJacopo Mondi 	ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops,
33747a3b8d4bSJacopo Mondi 					V4L2_CID_LINK_FREQ,
33757a3b8d4bSJacopo Mondi 					ARRAY_SIZE(ov5640_csi2_link_freqs) - 1,
33767a3b8d4bSJacopo Mondi 					OV5640_DEFAULT_LINK_FREQ,
33777a3b8d4bSJacopo Mondi 					ov5640_csi2_link_freqs);
33787a3b8d4bSJacopo Mondi 
337919a81c14SSteve Longerbeam 	/* Auto/manual white balance */
338019a81c14SSteve Longerbeam 	ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops,
338119a81c14SSteve Longerbeam 					   V4L2_CID_AUTO_WHITE_BALANCE,
338219a81c14SSteve Longerbeam 					   0, 1, 1, 1);
338319a81c14SSteve Longerbeam 	ctrls->blue_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BLUE_BALANCE,
338419a81c14SSteve Longerbeam 						0, 4095, 1, 0);
338519a81c14SSteve Longerbeam 	ctrls->red_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_RED_BALANCE,
338619a81c14SSteve Longerbeam 					       0, 4095, 1, 0);
338719a81c14SSteve Longerbeam 	/* Auto/manual exposure */
338819a81c14SSteve Longerbeam 	ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops,
338919a81c14SSteve Longerbeam 						 V4L2_CID_EXPOSURE_AUTO,
339019a81c14SSteve Longerbeam 						 V4L2_EXPOSURE_MANUAL, 0,
339119a81c14SSteve Longerbeam 						 V4L2_EXPOSURE_AUTO);
339219a81c14SSteve Longerbeam 	ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
339319a81c14SSteve Longerbeam 					    0, 65535, 1, 0);
339419a81c14SSteve Longerbeam 	/* Auto/manual gain */
339519a81c14SSteve Longerbeam 	ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN,
339619a81c14SSteve Longerbeam 					     0, 1, 1, 1);
339719a81c14SSteve Longerbeam 	ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN,
339819a81c14SSteve Longerbeam 					0, 1023, 1, 0);
339919a81c14SSteve Longerbeam 
340019a81c14SSteve Longerbeam 	ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION,
340119a81c14SSteve Longerbeam 					      0, 255, 1, 64);
340219a81c14SSteve Longerbeam 	ctrls->hue = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HUE,
340319a81c14SSteve Longerbeam 				       0, 359, 1, 0);
340419a81c14SSteve Longerbeam 	ctrls->contrast = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST,
340519a81c14SSteve Longerbeam 					    0, 255, 1, 0);
340619a81c14SSteve Longerbeam 	ctrls->test_pattern =
340719a81c14SSteve Longerbeam 		v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN,
340819a81c14SSteve Longerbeam 					     ARRAY_SIZE(test_pattern_menu) - 1,
340919a81c14SSteve Longerbeam 					     0, 0, test_pattern_menu);
3410ce85705aSHugues Fruchet 	ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP,
3411ce85705aSHugues Fruchet 					 0, 1, 1, 0);
3412ce85705aSHugues Fruchet 	ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP,
3413ce85705aSHugues Fruchet 					 0, 1, 1, 0);
341419a81c14SSteve Longerbeam 
34151068fecaSMylène Josserand 	ctrls->light_freq =
34161068fecaSMylène Josserand 		v4l2_ctrl_new_std_menu(hdl, ops,
34171068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY,
34181068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
34191068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
34201068fecaSMylène Josserand 
342119a81c14SSteve Longerbeam 	if (hdl->error) {
342219a81c14SSteve Longerbeam 		ret = hdl->error;
342319a81c14SSteve Longerbeam 		goto free_ctrls;
342419a81c14SSteve Longerbeam 	}
342519a81c14SSteve Longerbeam 
3426cc196e48SBenoit Parrot 	ctrls->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY;
34277a3b8d4bSJacopo Mondi 	ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
342819a81c14SSteve Longerbeam 	ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE;
342919a81c14SSteve Longerbeam 	ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE;
343019a81c14SSteve Longerbeam 
343119a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false);
343219a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(2, &ctrls->auto_gain, 0, true);
343319a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(2, &ctrls->auto_exp, 1, true);
343419a81c14SSteve Longerbeam 
343519a81c14SSteve Longerbeam 	sensor->sd.ctrl_handler = hdl;
343619a81c14SSteve Longerbeam 	return 0;
343719a81c14SSteve Longerbeam 
343819a81c14SSteve Longerbeam free_ctrls:
343919a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(hdl);
344019a81c14SSteve Longerbeam 	return ret;
344119a81c14SSteve Longerbeam }
344219a81c14SSteve Longerbeam 
344319a81c14SSteve Longerbeam static int ov5640_enum_frame_size(struct v4l2_subdev *sd,
34440d346d2aSTomi Valkeinen 				  struct v4l2_subdev_state *sd_state,
344519a81c14SSteve Longerbeam 				  struct v4l2_subdev_frame_size_enum *fse)
344619a81c14SSteve Longerbeam {
344719a81c14SSteve Longerbeam 	if (fse->pad != 0)
344819a81c14SSteve Longerbeam 		return -EINVAL;
344919a81c14SSteve Longerbeam 	if (fse->index >= OV5640_NUM_MODES)
345019a81c14SSteve Longerbeam 		return -EINVAL;
345119a81c14SSteve Longerbeam 
34525113d5b3SJacopo Mondi 	fse->min_width = ov5640_mode_data[fse->index].width;
345341d8d7f5SHugues Fruchet 	fse->max_width = fse->min_width;
34545113d5b3SJacopo Mondi 	fse->min_height = ov5640_mode_data[fse->index].height;
345541d8d7f5SHugues Fruchet 	fse->max_height = fse->min_height;
345619a81c14SSteve Longerbeam 
345719a81c14SSteve Longerbeam 	return 0;
345819a81c14SSteve Longerbeam }
345919a81c14SSteve Longerbeam 
346019a81c14SSteve Longerbeam static int ov5640_enum_frame_interval(
346119a81c14SSteve Longerbeam 	struct v4l2_subdev *sd,
34620d346d2aSTomi Valkeinen 	struct v4l2_subdev_state *sd_state,
346319a81c14SSteve Longerbeam 	struct v4l2_subdev_frame_interval_enum *fie)
346419a81c14SSteve Longerbeam {
346519a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
346619a81c14SSteve Longerbeam 	struct v4l2_fract tpf;
346719a81c14SSteve Longerbeam 	int ret;
346819a81c14SSteve Longerbeam 
346919a81c14SSteve Longerbeam 	if (fie->pad != 0)
347019a81c14SSteve Longerbeam 		return -EINVAL;
347119a81c14SSteve Longerbeam 	if (fie->index >= OV5640_NUM_FRAMERATES)
347219a81c14SSteve Longerbeam 		return -EINVAL;
347319a81c14SSteve Longerbeam 
347419a81c14SSteve Longerbeam 	tpf.numerator = 1;
347519a81c14SSteve Longerbeam 	tpf.denominator = ov5640_framerates[fie->index];
347619a81c14SSteve Longerbeam 
347719a81c14SSteve Longerbeam 	ret = ov5640_try_frame_interval(sensor, &tpf,
347819a81c14SSteve Longerbeam 					fie->width, fie->height);
347919a81c14SSteve Longerbeam 	if (ret < 0)
348019a81c14SSteve Longerbeam 		return -EINVAL;
348119a81c14SSteve Longerbeam 
348219a81c14SSteve Longerbeam 	fie->interval = tpf;
348319a81c14SSteve Longerbeam 	return 0;
348419a81c14SSteve Longerbeam }
348519a81c14SSteve Longerbeam 
348619a81c14SSteve Longerbeam static int ov5640_g_frame_interval(struct v4l2_subdev *sd,
348719a81c14SSteve Longerbeam 				   struct v4l2_subdev_frame_interval *fi)
348819a81c14SSteve Longerbeam {
348919a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
349019a81c14SSteve Longerbeam 
349119a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
349219a81c14SSteve Longerbeam 	fi->interval = sensor->frame_interval;
349319a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
349419a81c14SSteve Longerbeam 
349519a81c14SSteve Longerbeam 	return 0;
349619a81c14SSteve Longerbeam }
349719a81c14SSteve Longerbeam 
349819a81c14SSteve Longerbeam static int ov5640_s_frame_interval(struct v4l2_subdev *sd,
349919a81c14SSteve Longerbeam 				   struct v4l2_subdev_frame_interval *fi)
350019a81c14SSteve Longerbeam {
350119a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
350219a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
350319a81c14SSteve Longerbeam 	int frame_rate, ret = 0;
350419a81c14SSteve Longerbeam 
350519a81c14SSteve Longerbeam 	if (fi->pad != 0)
350619a81c14SSteve Longerbeam 		return -EINVAL;
350719a81c14SSteve Longerbeam 
350819a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
350919a81c14SSteve Longerbeam 
351019a81c14SSteve Longerbeam 	if (sensor->streaming) {
351119a81c14SSteve Longerbeam 		ret = -EBUSY;
351219a81c14SSteve Longerbeam 		goto out;
351319a81c14SSteve Longerbeam 	}
351419a81c14SSteve Longerbeam 
351519a81c14SSteve Longerbeam 	mode = sensor->current_mode;
351619a81c14SSteve Longerbeam 
351719a81c14SSteve Longerbeam 	frame_rate = ov5640_try_frame_interval(sensor, &fi->interval,
35185113d5b3SJacopo Mondi 					       mode->width,
35195113d5b3SJacopo Mondi 					       mode->height);
3520e823fb16SMaxime Ripard 	if (frame_rate < 0) {
3521e823fb16SMaxime Ripard 		/* Always return a valid frame interval value */
3522e823fb16SMaxime Ripard 		fi->interval = sensor->frame_interval;
3523e823fb16SMaxime Ripard 		goto out;
3524e823fb16SMaxime Ripard 	}
352519a81c14SSteve Longerbeam 
35265113d5b3SJacopo Mondi 	mode = ov5640_find_mode(sensor, frame_rate, mode->width,
35275113d5b3SJacopo Mondi 				mode->height, true);
35283c4a7372SHugues Fruchet 	if (!mode) {
35293c4a7372SHugues Fruchet 		ret = -EINVAL;
35303c4a7372SHugues Fruchet 		goto out;
35313c4a7372SHugues Fruchet 	}
35323c4a7372SHugues Fruchet 
35330929983eSHugues Fruchet 	if (mode != sensor->current_mode ||
35340929983eSHugues Fruchet 	    frame_rate != sensor->current_fr) {
35350929983eSHugues Fruchet 		sensor->current_fr = frame_rate;
35360929983eSHugues Fruchet 		sensor->frame_interval = fi->interval;
35373c4a7372SHugues Fruchet 		sensor->current_mode = mode;
353819a81c14SSteve Longerbeam 		sensor->pending_mode_change = true;
3539cc196e48SBenoit Parrot 
3540cc196e48SBenoit Parrot 		__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate,
3541cc196e48SBenoit Parrot 					 ov5640_calc_pixel_rate(sensor));
35426949d864SHugues Fruchet 	}
354319a81c14SSteve Longerbeam out:
354419a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
354519a81c14SSteve Longerbeam 	return ret;
354619a81c14SSteve Longerbeam }
354719a81c14SSteve Longerbeam 
354819a81c14SSteve Longerbeam static int ov5640_enum_mbus_code(struct v4l2_subdev *sd,
35490d346d2aSTomi Valkeinen 				 struct v4l2_subdev_state *sd_state,
355019a81c14SSteve Longerbeam 				 struct v4l2_subdev_mbus_code_enum *code)
355119a81c14SSteve Longerbeam {
355219a81c14SSteve Longerbeam 	if (code->pad != 0)
355319a81c14SSteve Longerbeam 		return -EINVAL;
3554e3ee691dSHugues Fruchet 	if (code->index >= ARRAY_SIZE(ov5640_formats))
355519a81c14SSteve Longerbeam 		return -EINVAL;
355619a81c14SSteve Longerbeam 
3557e3ee691dSHugues Fruchet 	code->code = ov5640_formats[code->index].code;
355819a81c14SSteve Longerbeam 	return 0;
355919a81c14SSteve Longerbeam }
356019a81c14SSteve Longerbeam 
356119a81c14SSteve Longerbeam static int ov5640_s_stream(struct v4l2_subdev *sd, int enable)
356219a81c14SSteve Longerbeam {
356319a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
356419a81c14SSteve Longerbeam 	int ret = 0;
356519a81c14SSteve Longerbeam 
356619a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
356719a81c14SSteve Longerbeam 
356819a81c14SSteve Longerbeam 	if (sensor->streaming == !enable) {
356919a81c14SSteve Longerbeam 		if (enable && sensor->pending_mode_change) {
3570985cdcb0SHugues Fruchet 			ret = ov5640_set_mode(sensor);
357119a81c14SSteve Longerbeam 			if (ret)
357219a81c14SSteve Longerbeam 				goto out;
3573fb98e29fSHugues Fruchet 		}
3574e3ee691dSHugues Fruchet 
3575fb98e29fSHugues Fruchet 		if (enable && sensor->pending_fmt_change) {
3576e3ee691dSHugues Fruchet 			ret = ov5640_set_framefmt(sensor, &sensor->fmt);
3577e3ee691dSHugues Fruchet 			if (ret)
3578e3ee691dSHugues Fruchet 				goto out;
3579fb98e29fSHugues Fruchet 			sensor->pending_fmt_change = false;
358019a81c14SSteve Longerbeam 		}
358119a81c14SSteve Longerbeam 
35828e823f5cSJacopo Mondi 		if (ov5640_is_csi2(sensor))
3583f22996dbSHugues Fruchet 			ret = ov5640_set_stream_mipi(sensor, enable);
3584f22996dbSHugues Fruchet 		else
3585f22996dbSHugues Fruchet 			ret = ov5640_set_stream_dvp(sensor, enable);
3586f22996dbSHugues Fruchet 
358719a81c14SSteve Longerbeam 		if (!ret)
358819a81c14SSteve Longerbeam 			sensor->streaming = enable;
358919a81c14SSteve Longerbeam 	}
359019a81c14SSteve Longerbeam out:
359119a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
359219a81c14SSteve Longerbeam 	return ret;
359319a81c14SSteve Longerbeam }
359419a81c14SSteve Longerbeam 
359519a81c14SSteve Longerbeam static const struct v4l2_subdev_core_ops ov5640_core_ops = {
359619a81c14SSteve Longerbeam 	.s_power = ov5640_s_power,
35972d18fbc5SAkinobu Mita 	.log_status = v4l2_ctrl_subdev_log_status,
35982d18fbc5SAkinobu Mita 	.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
35992d18fbc5SAkinobu Mita 	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
360019a81c14SSteve Longerbeam };
360119a81c14SSteve Longerbeam 
360219a81c14SSteve Longerbeam static const struct v4l2_subdev_video_ops ov5640_video_ops = {
360319a81c14SSteve Longerbeam 	.g_frame_interval = ov5640_g_frame_interval,
360419a81c14SSteve Longerbeam 	.s_frame_interval = ov5640_s_frame_interval,
360519a81c14SSteve Longerbeam 	.s_stream = ov5640_s_stream,
360619a81c14SSteve Longerbeam };
360719a81c14SSteve Longerbeam 
360819a81c14SSteve Longerbeam static const struct v4l2_subdev_pad_ops ov5640_pad_ops = {
360919a81c14SSteve Longerbeam 	.enum_mbus_code = ov5640_enum_mbus_code,
361019a81c14SSteve Longerbeam 	.get_fmt = ov5640_get_fmt,
361119a81c14SSteve Longerbeam 	.set_fmt = ov5640_set_fmt,
361219a81c14SSteve Longerbeam 	.enum_frame_size = ov5640_enum_frame_size,
361319a81c14SSteve Longerbeam 	.enum_frame_interval = ov5640_enum_frame_interval,
361419a81c14SSteve Longerbeam };
361519a81c14SSteve Longerbeam 
361619a81c14SSteve Longerbeam static const struct v4l2_subdev_ops ov5640_subdev_ops = {
361719a81c14SSteve Longerbeam 	.core = &ov5640_core_ops,
361819a81c14SSteve Longerbeam 	.video = &ov5640_video_ops,
361919a81c14SSteve Longerbeam 	.pad = &ov5640_pad_ops,
362019a81c14SSteve Longerbeam };
362119a81c14SSteve Longerbeam 
362219a81c14SSteve Longerbeam static int ov5640_get_regulators(struct ov5640_dev *sensor)
362319a81c14SSteve Longerbeam {
362419a81c14SSteve Longerbeam 	int i;
362519a81c14SSteve Longerbeam 
362619a81c14SSteve Longerbeam 	for (i = 0; i < OV5640_NUM_SUPPLIES; i++)
362719a81c14SSteve Longerbeam 		sensor->supplies[i].supply = ov5640_supply_name[i];
362819a81c14SSteve Longerbeam 
362919a81c14SSteve Longerbeam 	return devm_regulator_bulk_get(&sensor->i2c_client->dev,
363019a81c14SSteve Longerbeam 				       OV5640_NUM_SUPPLIES,
363119a81c14SSteve Longerbeam 				       sensor->supplies);
363219a81c14SSteve Longerbeam }
363319a81c14SSteve Longerbeam 
36340f7acb52SHugues Fruchet static int ov5640_check_chip_id(struct ov5640_dev *sensor)
36350f7acb52SHugues Fruchet {
36360f7acb52SHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
36370f7acb52SHugues Fruchet 	int ret = 0;
36380f7acb52SHugues Fruchet 	u16 chip_id;
36390f7acb52SHugues Fruchet 
36400f7acb52SHugues Fruchet 	ret = ov5640_set_power_on(sensor);
36410f7acb52SHugues Fruchet 	if (ret)
36420f7acb52SHugues Fruchet 		return ret;
36430f7acb52SHugues Fruchet 
36440f7acb52SHugues Fruchet 	ret = ov5640_read_reg16(sensor, OV5640_REG_CHIP_ID, &chip_id);
36450f7acb52SHugues Fruchet 	if (ret) {
36460f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to read chip identifier\n",
36470f7acb52SHugues Fruchet 			__func__);
36480f7acb52SHugues Fruchet 		goto power_off;
36490f7acb52SHugues Fruchet 	}
36500f7acb52SHugues Fruchet 
36510f7acb52SHugues Fruchet 	if (chip_id != 0x5640) {
36520f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: wrong chip identifier, expected 0x5640, got 0x%x\n",
36530f7acb52SHugues Fruchet 			__func__, chip_id);
36540f7acb52SHugues Fruchet 		ret = -ENXIO;
36550f7acb52SHugues Fruchet 	}
36560f7acb52SHugues Fruchet 
36570f7acb52SHugues Fruchet power_off:
36580f7acb52SHugues Fruchet 	ov5640_set_power_off(sensor);
36590f7acb52SHugues Fruchet 	return ret;
36600f7acb52SHugues Fruchet }
36610f7acb52SHugues Fruchet 
3662e6714993SKieran Bingham static int ov5640_probe(struct i2c_client *client)
366319a81c14SSteve Longerbeam {
366419a81c14SSteve Longerbeam 	struct device *dev = &client->dev;
366519a81c14SSteve Longerbeam 	struct fwnode_handle *endpoint;
366619a81c14SSteve Longerbeam 	struct ov5640_dev *sensor;
3667e6441fdeSHugues Fruchet 	struct v4l2_mbus_framefmt *fmt;
3668c3f3ba3eSHugues Fruchet 	u32 rotation;
366919a81c14SSteve Longerbeam 	int ret;
367019a81c14SSteve Longerbeam 
367119a81c14SSteve Longerbeam 	sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
367219a81c14SSteve Longerbeam 	if (!sensor)
367319a81c14SSteve Longerbeam 		return -ENOMEM;
367419a81c14SSteve Longerbeam 
367519a81c14SSteve Longerbeam 	sensor->i2c_client = client;
3676fb98e29fSHugues Fruchet 
3677fb98e29fSHugues Fruchet 	/*
3678fb98e29fSHugues Fruchet 	 * default init sequence initialize sensor to
3679fb98e29fSHugues Fruchet 	 * YUV422 UYVY VGA@30fps
3680fb98e29fSHugues Fruchet 	 */
3681e6441fdeSHugues Fruchet 	fmt = &sensor->fmt;
3682fb98e29fSHugues Fruchet 	fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
3683fb98e29fSHugues Fruchet 	fmt->colorspace = V4L2_COLORSPACE_SRGB;
3684e6441fdeSHugues Fruchet 	fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
3685e6441fdeSHugues Fruchet 	fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
3686e6441fdeSHugues Fruchet 	fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
3687e6441fdeSHugues Fruchet 	fmt->width = 640;
3688e6441fdeSHugues Fruchet 	fmt->height = 480;
3689e6441fdeSHugues Fruchet 	fmt->field = V4L2_FIELD_NONE;
369019a81c14SSteve Longerbeam 	sensor->frame_interval.numerator = 1;
369119a81c14SSteve Longerbeam 	sensor->frame_interval.denominator = ov5640_framerates[OV5640_30_FPS];
369219a81c14SSteve Longerbeam 	sensor->current_fr = OV5640_30_FPS;
369319a81c14SSteve Longerbeam 	sensor->current_mode =
3694086c25f8SMaxime Ripard 		&ov5640_mode_data[OV5640_MODE_VGA_640_480];
3695985cdcb0SHugues Fruchet 	sensor->last_mode = sensor->current_mode;
36963c28588fSJacopo Mondi 	sensor->current_link_freq = OV5640_DEFAULT_LINK_FREQ;
369719a81c14SSteve Longerbeam 
369819a81c14SSteve Longerbeam 	sensor->ae_target = 52;
369919a81c14SSteve Longerbeam 
3700c3f3ba3eSHugues Fruchet 	/* optional indication of physical rotation of sensor */
3701c3f3ba3eSHugues Fruchet 	ret = fwnode_property_read_u32(dev_fwnode(&client->dev), "rotation",
3702c3f3ba3eSHugues Fruchet 				       &rotation);
3703c3f3ba3eSHugues Fruchet 	if (!ret) {
3704c3f3ba3eSHugues Fruchet 		switch (rotation) {
3705c3f3ba3eSHugues Fruchet 		case 180:
3706c3f3ba3eSHugues Fruchet 			sensor->upside_down = true;
37071771e9fbSGustavo A. R. Silva 			fallthrough;
3708c3f3ba3eSHugues Fruchet 		case 0:
3709c3f3ba3eSHugues Fruchet 			break;
3710c3f3ba3eSHugues Fruchet 		default:
3711c3f3ba3eSHugues Fruchet 			dev_warn(dev, "%u degrees rotation is not supported, ignoring...\n",
3712c3f3ba3eSHugues Fruchet 				 rotation);
3713c3f3ba3eSHugues Fruchet 		}
3714c3f3ba3eSHugues Fruchet 	}
3715c3f3ba3eSHugues Fruchet 
3716ce96bcf5SSakari Ailus 	endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev),
3717ce96bcf5SSakari Ailus 						  NULL);
371819a81c14SSteve Longerbeam 	if (!endpoint) {
371919a81c14SSteve Longerbeam 		dev_err(dev, "endpoint node not found\n");
372019a81c14SSteve Longerbeam 		return -EINVAL;
372119a81c14SSteve Longerbeam 	}
372219a81c14SSteve Longerbeam 
372319a81c14SSteve Longerbeam 	ret = v4l2_fwnode_endpoint_parse(endpoint, &sensor->ep);
372419a81c14SSteve Longerbeam 	fwnode_handle_put(endpoint);
372519a81c14SSteve Longerbeam 	if (ret) {
372619a81c14SSteve Longerbeam 		dev_err(dev, "Could not parse endpoint\n");
372719a81c14SSteve Longerbeam 		return ret;
372819a81c14SSteve Longerbeam 	}
372919a81c14SSteve Longerbeam 
37302c61e48dSLad Prabhakar 	if (sensor->ep.bus_type != V4L2_MBUS_PARALLEL &&
37312c61e48dSLad Prabhakar 	    sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY &&
37322c61e48dSLad Prabhakar 	    sensor->ep.bus_type != V4L2_MBUS_BT656) {
37332c61e48dSLad Prabhakar 		dev_err(dev, "Unsupported bus type %d\n", sensor->ep.bus_type);
37342c61e48dSLad Prabhakar 		return -EINVAL;
37352c61e48dSLad Prabhakar 	}
37362c61e48dSLad Prabhakar 
373719a81c14SSteve Longerbeam 	/* get system clock (xclk) */
373819a81c14SSteve Longerbeam 	sensor->xclk = devm_clk_get(dev, "xclk");
373919a81c14SSteve Longerbeam 	if (IS_ERR(sensor->xclk)) {
374019a81c14SSteve Longerbeam 		dev_err(dev, "failed to get xclk\n");
374119a81c14SSteve Longerbeam 		return PTR_ERR(sensor->xclk);
374219a81c14SSteve Longerbeam 	}
374319a81c14SSteve Longerbeam 
374419a81c14SSteve Longerbeam 	sensor->xclk_freq = clk_get_rate(sensor->xclk);
374519a81c14SSteve Longerbeam 	if (sensor->xclk_freq < OV5640_XCLK_MIN ||
374619a81c14SSteve Longerbeam 	    sensor->xclk_freq > OV5640_XCLK_MAX) {
374719a81c14SSteve Longerbeam 		dev_err(dev, "xclk frequency out of range: %d Hz\n",
374819a81c14SSteve Longerbeam 			sensor->xclk_freq);
374919a81c14SSteve Longerbeam 		return -EINVAL;
375019a81c14SSteve Longerbeam 	}
375119a81c14SSteve Longerbeam 
375219a81c14SSteve Longerbeam 	/* request optional power down pin */
375319a81c14SSteve Longerbeam 	sensor->pwdn_gpio = devm_gpiod_get_optional(dev, "powerdown",
375419a81c14SSteve Longerbeam 						    GPIOD_OUT_HIGH);
37558791a102SFabio Estevam 	if (IS_ERR(sensor->pwdn_gpio))
37568791a102SFabio Estevam 		return PTR_ERR(sensor->pwdn_gpio);
37578791a102SFabio Estevam 
375819a81c14SSteve Longerbeam 	/* request optional reset pin */
375919a81c14SSteve Longerbeam 	sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset",
376019a81c14SSteve Longerbeam 						     GPIOD_OUT_HIGH);
37618791a102SFabio Estevam 	if (IS_ERR(sensor->reset_gpio))
37628791a102SFabio Estevam 		return PTR_ERR(sensor->reset_gpio);
376319a81c14SSteve Longerbeam 
376419a81c14SSteve Longerbeam 	v4l2_i2c_subdev_init(&sensor->sd, client, &ov5640_subdev_ops);
376519a81c14SSteve Longerbeam 
37662d18fbc5SAkinobu Mita 	sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
37672d18fbc5SAkinobu Mita 			    V4L2_SUBDEV_FL_HAS_EVENTS;
376819a81c14SSteve Longerbeam 	sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
376919a81c14SSteve Longerbeam 	sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
377019a81c14SSteve Longerbeam 	ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
377119a81c14SSteve Longerbeam 	if (ret)
377219a81c14SSteve Longerbeam 		return ret;
377319a81c14SSteve Longerbeam 
377419a81c14SSteve Longerbeam 	ret = ov5640_get_regulators(sensor);
377519a81c14SSteve Longerbeam 	if (ret)
377619a81c14SSteve Longerbeam 		return ret;
377719a81c14SSteve Longerbeam 
377819a81c14SSteve Longerbeam 	mutex_init(&sensor->lock);
377919a81c14SSteve Longerbeam 
37800f7acb52SHugues Fruchet 	ret = ov5640_check_chip_id(sensor);
37810f7acb52SHugues Fruchet 	if (ret)
37820f7acb52SHugues Fruchet 		goto entity_cleanup;
37830f7acb52SHugues Fruchet 
378419a81c14SSteve Longerbeam 	ret = ov5640_init_controls(sensor);
378519a81c14SSteve Longerbeam 	if (ret)
378619a81c14SSteve Longerbeam 		goto entity_cleanup;
378719a81c14SSteve Longerbeam 
378815786f7bSSakari Ailus 	ret = v4l2_async_register_subdev_sensor(&sensor->sd);
378919a81c14SSteve Longerbeam 	if (ret)
379019a81c14SSteve Longerbeam 		goto free_ctrls;
379119a81c14SSteve Longerbeam 
379219a81c14SSteve Longerbeam 	return 0;
379319a81c14SSteve Longerbeam 
379419a81c14SSteve Longerbeam free_ctrls:
379519a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
379619a81c14SSteve Longerbeam entity_cleanup:
379719a81c14SSteve Longerbeam 	media_entity_cleanup(&sensor->sd.entity);
3798bfcba38dSTomi Valkeinen 	mutex_destroy(&sensor->lock);
379919a81c14SSteve Longerbeam 	return ret;
380019a81c14SSteve Longerbeam }
380119a81c14SSteve Longerbeam 
380219a81c14SSteve Longerbeam static int ov5640_remove(struct i2c_client *client)
380319a81c14SSteve Longerbeam {
380419a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
380519a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
380619a81c14SSteve Longerbeam 
380719a81c14SSteve Longerbeam 	v4l2_async_unregister_subdev(&sensor->sd);
380819a81c14SSteve Longerbeam 	media_entity_cleanup(&sensor->sd.entity);
380919a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
3810bfcba38dSTomi Valkeinen 	mutex_destroy(&sensor->lock);
381119a81c14SSteve Longerbeam 
381219a81c14SSteve Longerbeam 	return 0;
381319a81c14SSteve Longerbeam }
381419a81c14SSteve Longerbeam 
381519a81c14SSteve Longerbeam static const struct i2c_device_id ov5640_id[] = {
381619a81c14SSteve Longerbeam 	{"ov5640", 0},
381719a81c14SSteve Longerbeam 	{},
381819a81c14SSteve Longerbeam };
381919a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(i2c, ov5640_id);
382019a81c14SSteve Longerbeam 
382119a81c14SSteve Longerbeam static const struct of_device_id ov5640_dt_ids[] = {
382219a81c14SSteve Longerbeam 	{ .compatible = "ovti,ov5640" },
382319a81c14SSteve Longerbeam 	{ /* sentinel */ }
382419a81c14SSteve Longerbeam };
382519a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(of, ov5640_dt_ids);
382619a81c14SSteve Longerbeam 
382719a81c14SSteve Longerbeam static struct i2c_driver ov5640_i2c_driver = {
382819a81c14SSteve Longerbeam 	.driver = {
382919a81c14SSteve Longerbeam 		.name  = "ov5640",
383019a81c14SSteve Longerbeam 		.of_match_table	= ov5640_dt_ids,
383119a81c14SSteve Longerbeam 	},
383219a81c14SSteve Longerbeam 	.id_table = ov5640_id,
3833e6714993SKieran Bingham 	.probe_new = ov5640_probe,
383419a81c14SSteve Longerbeam 	.remove   = ov5640_remove,
383519a81c14SSteve Longerbeam };
383619a81c14SSteve Longerbeam 
383719a81c14SSteve Longerbeam module_i2c_driver(ov5640_i2c_driver);
383819a81c14SSteve Longerbeam 
383919a81c14SSteve Longerbeam MODULE_DESCRIPTION("OV5640 MIPI Camera Subdev Driver");
384019a81c14SSteve Longerbeam MODULE_LICENSE("GPL");
3841