xref: /openbmc/linux/drivers/media/i2c/ov5640.c (revision 90b0f355)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
219a81c14SSteve Longerbeam /*
319a81c14SSteve Longerbeam  * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
419a81c14SSteve Longerbeam  * Copyright (C) 2014-2017 Mentor Graphics Inc.
519a81c14SSteve Longerbeam  */
619a81c14SSteve Longerbeam 
719a81c14SSteve Longerbeam #include <linux/clk.h>
819a81c14SSteve Longerbeam #include <linux/clk-provider.h>
919a81c14SSteve Longerbeam #include <linux/clkdev.h>
1019a81c14SSteve Longerbeam #include <linux/ctype.h>
1119a81c14SSteve Longerbeam #include <linux/delay.h>
1219a81c14SSteve Longerbeam #include <linux/device.h>
1341d8d7f5SHugues Fruchet #include <linux/gpio/consumer.h>
1419a81c14SSteve Longerbeam #include <linux/i2c.h>
1519a81c14SSteve Longerbeam #include <linux/init.h>
1619a81c14SSteve Longerbeam #include <linux/module.h>
1719a81c14SSteve Longerbeam #include <linux/of_device.h>
1841d8d7f5SHugues Fruchet #include <linux/regulator/consumer.h>
1919a81c14SSteve Longerbeam #include <linux/slab.h>
2019a81c14SSteve Longerbeam #include <linux/types.h>
2119a81c14SSteve Longerbeam #include <media/v4l2-async.h>
2219a81c14SSteve Longerbeam #include <media/v4l2-ctrls.h>
2319a81c14SSteve Longerbeam #include <media/v4l2-device.h>
242d18fbc5SAkinobu Mita #include <media/v4l2-event.h>
2519a81c14SSteve Longerbeam #include <media/v4l2-fwnode.h>
2619a81c14SSteve Longerbeam #include <media/v4l2-subdev.h>
2719a81c14SSteve Longerbeam 
2819a81c14SSteve Longerbeam /* min/typical/max system clock (xclk) frequencies */
2919a81c14SSteve Longerbeam #define OV5640_XCLK_MIN  6000000
3041cb1c73SPhilipp Puschmann #define OV5640_XCLK_MAX 54000000
3119a81c14SSteve Longerbeam 
325113d5b3SJacopo Mondi #define OV5640_NATIVE_WIDTH		2624
335113d5b3SJacopo Mondi #define OV5640_NATIVE_HEIGHT		1964
345113d5b3SJacopo Mondi #define OV5640_PIXEL_ARRAY_TOP		14
355113d5b3SJacopo Mondi #define OV5640_PIXEL_ARRAY_LEFT		16
365113d5b3SJacopo Mondi #define OV5640_PIXEL_ARRAY_WIDTH	2592
375113d5b3SJacopo Mondi #define OV5640_PIXEL_ARRAY_HEIGHT	1944
385113d5b3SJacopo Mondi 
39bce93b82SJacopo Mondi /* FIXME: not documented. */
40bce93b82SJacopo Mondi #define OV5640_MIN_VBLANK	24
41bce93b82SJacopo Mondi #define OV5640_MAX_VTS		3375
42bce93b82SJacopo Mondi 
4319a81c14SSteve Longerbeam #define OV5640_DEFAULT_SLAVE_ID 0x3c
4419a81c14SSteve Longerbeam 
453c28588fSJacopo Mondi #define OV5640_LINK_RATE_MAX		490000000U
463c28588fSJacopo Mondi 
47d47c4126SHugues Fruchet #define OV5640_REG_SYS_RESET02		0x3002
48d47c4126SHugues Fruchet #define OV5640_REG_SYS_CLOCK_ENABLE02	0x3006
49f22996dbSHugues Fruchet #define OV5640_REG_SYS_CTRL0		0x3008
503b987d70SLad Prabhakar #define OV5640_REG_SYS_CTRL0_SW_PWDN	0x42
513b987d70SLad Prabhakar #define OV5640_REG_SYS_CTRL0_SW_PWUP	0x02
5219a81c14SSteve Longerbeam #define OV5640_REG_CHIP_ID		0x300a
53f22996dbSHugues Fruchet #define OV5640_REG_IO_MIPI_CTRL00	0x300e
54f22996dbSHugues Fruchet #define OV5640_REG_PAD_OUTPUT_ENABLE01	0x3017
55f22996dbSHugues Fruchet #define OV5640_REG_PAD_OUTPUT_ENABLE02	0x3018
5619a81c14SSteve Longerbeam #define OV5640_REG_PAD_OUTPUT00		0x3019
57f22996dbSHugues Fruchet #define OV5640_REG_SYSTEM_CONTROL1	0x302e
5819a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL0		0x3034
5919a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL1		0x3035
6019a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL2		0x3036
6119a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL3		0x3037
6219a81c14SSteve Longerbeam #define OV5640_REG_SLAVE_ID		0x3100
63f22996dbSHugues Fruchet #define OV5640_REG_SCCB_SYS_CTRL1	0x3103
6419a81c14SSteve Longerbeam #define OV5640_REG_SYS_ROOT_DIVIDER	0x3108
6519a81c14SSteve Longerbeam #define OV5640_REG_AWB_R_GAIN		0x3400
6619a81c14SSteve Longerbeam #define OV5640_REG_AWB_G_GAIN		0x3402
6719a81c14SSteve Longerbeam #define OV5640_REG_AWB_B_GAIN		0x3404
6819a81c14SSteve Longerbeam #define OV5640_REG_AWB_MANUAL_CTRL	0x3406
6919a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_HI	0x3500
7019a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_MED	0x3501
7119a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_LO	0x3502
7219a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_MANUAL	0x3503
7319a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_REAL_GAIN	0x350a
7419a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_VTS		0x350c
753145efcdSJacopo Mondi #define OV5640_REG_TIMING_HS		0x3800
763145efcdSJacopo Mondi #define OV5640_REG_TIMING_VS		0x3802
773145efcdSJacopo Mondi #define OV5640_REG_TIMING_HW		0x3804
783145efcdSJacopo Mondi #define OV5640_REG_TIMING_VH		0x3806
7986633417SMaxime Ripard #define OV5640_REG_TIMING_DVPHO		0x3808
8086633417SMaxime Ripard #define OV5640_REG_TIMING_DVPVO		0x380a
8119a81c14SSteve Longerbeam #define OV5640_REG_TIMING_HTS		0x380c
8219a81c14SSteve Longerbeam #define OV5640_REG_TIMING_VTS		0x380e
833145efcdSJacopo Mondi #define OV5640_REG_TIMING_HOFFS		0x3810
843145efcdSJacopo Mondi #define OV5640_REG_TIMING_VOFFS		0x3812
85ce85705aSHugues Fruchet #define OV5640_REG_TIMING_TC_REG20	0x3820
8619a81c14SSteve Longerbeam #define OV5640_REG_TIMING_TC_REG21	0x3821
8719a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL00		0x3a00
8819a81c14SSteve Longerbeam #define OV5640_REG_AEC_B50_STEP		0x3a08
8919a81c14SSteve Longerbeam #define OV5640_REG_AEC_B60_STEP		0x3a0a
9019a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0D		0x3a0d
9119a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0E		0x3a0e
9219a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0F		0x3a0f
9319a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL10		0x3a10
9419a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL11		0x3a11
9519a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1B		0x3a1b
9619a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1E		0x3a1e
9719a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1F		0x3a1f
9819a81c14SSteve Longerbeam #define OV5640_REG_HZ5060_CTRL00	0x3c00
9919a81c14SSteve Longerbeam #define OV5640_REG_HZ5060_CTRL01	0x3c01
10019a81c14SSteve Longerbeam #define OV5640_REG_SIGMADELTA_CTRL0C	0x3c0c
10119a81c14SSteve Longerbeam #define OV5640_REG_FRAME_CTRL01		0x4202
102e3ee691dSHugues Fruchet #define OV5640_REG_FORMAT_CONTROL00	0x4300
1037cb013b1SChen-Yu Tsai #define OV5640_REG_VFIFO_HSIZE		0x4602
1047cb013b1SChen-Yu Tsai #define OV5640_REG_VFIFO_VSIZE		0x4604
1052b5c18f9SChen-Yu Tsai #define OV5640_REG_JPG_MODE_SELECT	0x4713
1064039b037SLad Prabhakar #define OV5640_REG_CCIR656_CTRL00	0x4730
107f22996dbSHugues Fruchet #define OV5640_REG_POLARITY_CTRL00	0x4740
10819a81c14SSteve Longerbeam #define OV5640_REG_MIPI_CTRL00		0x4800
10919a81c14SSteve Longerbeam #define OV5640_REG_DEBUG_MODE		0x4814
1106c957ed7SJacopo Mondi #define OV5640_REG_PCLK_PERIOD		0x4837
111e3ee691dSHugues Fruchet #define OV5640_REG_ISP_FORMAT_MUX_CTRL	0x501f
11219a81c14SSteve Longerbeam #define OV5640_REG_PRE_ISP_TEST_SET1	0x503d
11319a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL0		0x5580
11419a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL1		0x5581
11519a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL3		0x5583
11619a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL4		0x5584
11719a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL5		0x5585
11819a81c14SSteve Longerbeam #define OV5640_REG_AVG_READOUT		0x56a1
11919a81c14SSteve Longerbeam 
12019a81c14SSteve Longerbeam enum ov5640_mode_id {
12132ea5e05SHugues Fruchet 	OV5640_MODE_QQVGA_160_120 = 0,
12232ea5e05SHugues Fruchet 	OV5640_MODE_QCIF_176_144,
12319a81c14SSteve Longerbeam 	OV5640_MODE_QVGA_320_240,
12419a81c14SSteve Longerbeam 	OV5640_MODE_VGA_640_480,
12519a81c14SSteve Longerbeam 	OV5640_MODE_NTSC_720_480,
12619a81c14SSteve Longerbeam 	OV5640_MODE_PAL_720_576,
12719a81c14SSteve Longerbeam 	OV5640_MODE_XGA_1024_768,
12819a81c14SSteve Longerbeam 	OV5640_MODE_720P_1280_720,
12919a81c14SSteve Longerbeam 	OV5640_MODE_1080P_1920_1080,
13019a81c14SSteve Longerbeam 	OV5640_MODE_QSXGA_2592_1944,
13119a81c14SSteve Longerbeam 	OV5640_NUM_MODES,
13219a81c14SSteve Longerbeam };
13319a81c14SSteve Longerbeam 
13419a81c14SSteve Longerbeam enum ov5640_frame_rate {
13519a81c14SSteve Longerbeam 	OV5640_15_FPS = 0,
13619a81c14SSteve Longerbeam 	OV5640_30_FPS,
137e823fb16SMaxime Ripard 	OV5640_60_FPS,
13819a81c14SSteve Longerbeam 	OV5640_NUM_FRAMERATES,
13919a81c14SSteve Longerbeam };
14019a81c14SSteve Longerbeam 
14122845bf2SJacopo Mondi enum ov5640_pixel_rate_id {
14222845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_168M,
14322845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_148M,
14422845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_124M,
14522845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_96M,
14622845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_48M,
14722845bf2SJacopo Mondi 	OV5640_NUM_PIXEL_RATES,
14822845bf2SJacopo Mondi };
14922845bf2SJacopo Mondi 
15022845bf2SJacopo Mondi /*
15122845bf2SJacopo Mondi  * The chip manual suggests 24/48/96/192 MHz pixel clocks.
15222845bf2SJacopo Mondi  *
15322845bf2SJacopo Mondi  * 192MHz exceeds the sysclk limits; use 168MHz as maximum pixel rate for
15422845bf2SJacopo Mondi  * full resolution mode @15 FPS.
15522845bf2SJacopo Mondi  */
15622845bf2SJacopo Mondi static const u32 ov5640_pixel_rates[] = {
15722845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_168M] = 168000000,
15822845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_148M] = 148000000,
15922845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_124M] = 124000000,
16022845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_96M] = 96000000,
16122845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_48M] = 48000000,
16222845bf2SJacopo Mondi };
16322845bf2SJacopo Mondi 
1647a3b8d4bSJacopo Mondi /*
1657a3b8d4bSJacopo Mondi  * MIPI CSI-2 link frequencies.
1667a3b8d4bSJacopo Mondi  *
1677a3b8d4bSJacopo Mondi  * Derived from the above defined pixel rate for bpp = (8, 16, 24) and
1687a3b8d4bSJacopo Mondi  * data_lanes = (1, 2)
1697a3b8d4bSJacopo Mondi  *
1707a3b8d4bSJacopo Mondi  * link_freq = (pixel_rate * bpp) / (2 * data_lanes)
1717a3b8d4bSJacopo Mondi  */
1727a3b8d4bSJacopo Mondi static const s64 ov5640_csi2_link_freqs[] = {
1737a3b8d4bSJacopo Mondi 	992000000, 888000000, 768000000, 744000000, 672000000, 672000000,
1747a3b8d4bSJacopo Mondi 	592000000, 592000000, 576000000, 576000000, 496000000, 496000000,
1757a3b8d4bSJacopo Mondi 	384000000, 384000000, 384000000, 336000000, 296000000, 288000000,
1767a3b8d4bSJacopo Mondi 	248000000, 192000000, 192000000, 192000000, 96000000,
1777a3b8d4bSJacopo Mondi };
1787a3b8d4bSJacopo Mondi 
1797a3b8d4bSJacopo Mondi /* Link freq for default mode: UYVY 16 bpp, 2 data lanes. */
1807a3b8d4bSJacopo Mondi #define OV5640_DEFAULT_LINK_FREQ	13
1817a3b8d4bSJacopo Mondi 
182b7ed3abdSLoic Poulain enum ov5640_format_mux {
183b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_YUV422 = 0,
184b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_RGB,
185b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_DITHER,
186b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_RAW_DPC,
187b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_SNR_RAW,
188b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_RAW_CIP,
189b7ed3abdSLoic Poulain };
190b7ed3abdSLoic Poulain 
1912d7671f6SJacopo Mondi static const struct ov5640_pixfmt {
192e3ee691dSHugues Fruchet 	u32 code;
193e3ee691dSHugues Fruchet 	u32 colorspace;
1942d7671f6SJacopo Mondi 	u8 bpp;
1952d7671f6SJacopo Mondi } ov5640_formats[] = {
1962d7671f6SJacopo Mondi 	{
1972d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_JPEG_1X8,
1982d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_JPEG,
1992d7671f6SJacopo Mondi 		.bpp = 16,
2002d7671f6SJacopo Mondi 	}, {
2012d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_UYVY8_2X8,
2022d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2032d7671f6SJacopo Mondi 		.bpp = 16,
2042d7671f6SJacopo Mondi 	}, {
2052d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_UYVY8_1X16,
2062d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2072d7671f6SJacopo Mondi 		.bpp = 16,
2082d7671f6SJacopo Mondi 	}, {
2092d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_YUYV8_2X8,
2102d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2112d7671f6SJacopo Mondi 		.bpp = 16,
2122d7671f6SJacopo Mondi 	}, {
2132d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_YUYV8_1X16,
2142d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2152d7671f6SJacopo Mondi 		.bpp = 16,
2162d7671f6SJacopo Mondi 	}, {
2172d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_RGB565_2X8_LE,
2182d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2192d7671f6SJacopo Mondi 		.bpp = 16,
2202d7671f6SJacopo Mondi 	}, {
2212d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_RGB565_2X8_BE,
2222d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2232d7671f6SJacopo Mondi 		.bpp = 16,
2242d7671f6SJacopo Mondi 	}, {
2252d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_SBGGR8_1X8,
2262d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2272d7671f6SJacopo Mondi 		.bpp = 8,
2282d7671f6SJacopo Mondi 	}, {
2292d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_SGBRG8_1X8,
2302d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2312d7671f6SJacopo Mondi 		.bpp = 8
2322d7671f6SJacopo Mondi 	}, {
2332d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_SGRBG8_1X8,
2342d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2352d7671f6SJacopo Mondi 		.bpp = 8,
2362d7671f6SJacopo Mondi 	}, {
2372d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_SRGGB8_1X8,
2382d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2392d7671f6SJacopo Mondi 		.bpp = 8,
2402d7671f6SJacopo Mondi 	},
241e3ee691dSHugues Fruchet };
242e3ee691dSHugues Fruchet 
2433c28588fSJacopo Mondi static u32 ov5640_code_to_bpp(u32 code)
2443c28588fSJacopo Mondi {
2453c28588fSJacopo Mondi 	unsigned int i;
2463c28588fSJacopo Mondi 
2473c28588fSJacopo Mondi 	for (i = 0; i < ARRAY_SIZE(ov5640_formats); ++i) {
2483c28588fSJacopo Mondi 		if (ov5640_formats[i].code == code)
2493c28588fSJacopo Mondi 			return ov5640_formats[i].bpp;
2503c28588fSJacopo Mondi 	}
2513c28588fSJacopo Mondi 
2523c28588fSJacopo Mondi 	return 0;
2533c28588fSJacopo Mondi }
2543c28588fSJacopo Mondi 
25519a81c14SSteve Longerbeam /*
25619a81c14SSteve Longerbeam  * FIXME: remove this when a subdev API becomes available
25719a81c14SSteve Longerbeam  * to set the MIPI CSI-2 virtual channel.
25819a81c14SSteve Longerbeam  */
25919a81c14SSteve Longerbeam static unsigned int virtual_channel;
2608670d70aSHugues Fruchet module_param(virtual_channel, uint, 0444);
26119a81c14SSteve Longerbeam MODULE_PARM_DESC(virtual_channel,
26219a81c14SSteve Longerbeam 		 "MIPI CSI-2 virtual channel (0..3), default 0");
26319a81c14SSteve Longerbeam 
26419a81c14SSteve Longerbeam static const int ov5640_framerates[] = {
26519a81c14SSteve Longerbeam 	[OV5640_15_FPS] = 15,
26619a81c14SSteve Longerbeam 	[OV5640_30_FPS] = 30,
267e823fb16SMaxime Ripard 	[OV5640_60_FPS] = 60,
26819a81c14SSteve Longerbeam };
26919a81c14SSteve Longerbeam 
27019a81c14SSteve Longerbeam /* regulator supplies */
27119a81c14SSteve Longerbeam static const char * const ov5640_supply_name[] = {
27241d8d7f5SHugues Fruchet 	"DOVDD", /* Digital I/O (1.8V) supply */
27319a81c14SSteve Longerbeam 	"AVDD",  /* Analog (2.8V) supply */
27424c8ac89SFabio Estevam 	"DVDD",  /* Digital Core (1.5V) supply */
27519a81c14SSteve Longerbeam };
27619a81c14SSteve Longerbeam 
27719a81c14SSteve Longerbeam #define OV5640_NUM_SUPPLIES ARRAY_SIZE(ov5640_supply_name)
27819a81c14SSteve Longerbeam 
27919a81c14SSteve Longerbeam /*
28019a81c14SSteve Longerbeam  * Image size under 1280 * 960 are SUBSAMPLING
28119a81c14SSteve Longerbeam  * Image size upper 1280 * 960 are SCALING
28219a81c14SSteve Longerbeam  */
28319a81c14SSteve Longerbeam enum ov5640_downsize_mode {
28419a81c14SSteve Longerbeam 	SUBSAMPLING,
28519a81c14SSteve Longerbeam 	SCALING,
28619a81c14SSteve Longerbeam };
28719a81c14SSteve Longerbeam 
28819a81c14SSteve Longerbeam struct reg_value {
28919a81c14SSteve Longerbeam 	u16 reg_addr;
29019a81c14SSteve Longerbeam 	u8 val;
29119a81c14SSteve Longerbeam 	u8 mask;
29219a81c14SSteve Longerbeam 	u32 delay_ms;
29319a81c14SSteve Longerbeam };
29419a81c14SSteve Longerbeam 
2955113d5b3SJacopo Mondi struct ov5640_timings {
2963145efcdSJacopo Mondi 	/* Analog crop rectangle. */
2973145efcdSJacopo Mondi 	struct v4l2_rect analog_crop;
2983145efcdSJacopo Mondi 	/* Visibile crop: from analog crop top-left corner. */
2993145efcdSJacopo Mondi 	struct v4l2_rect crop;
3005113d5b3SJacopo Mondi 	/* Total pixels per line: width + fixed hblank. */
301476dec01SMaxime Ripard 	u32 htot;
3025113d5b3SJacopo Mondi 	/* Default vertical blanking: frame height = height + vblank. */
3033145efcdSJacopo Mondi 	u32 vblank_def;
3045113d5b3SJacopo Mondi };
3055113d5b3SJacopo Mondi 
3065113d5b3SJacopo Mondi struct ov5640_mode_info {
3075113d5b3SJacopo Mondi 	enum ov5640_mode_id id;
3085113d5b3SJacopo Mondi 	enum ov5640_downsize_mode dn_mode;
3095113d5b3SJacopo Mondi 	enum ov5640_pixel_rate_id pixel_rate;
3105113d5b3SJacopo Mondi 
3115113d5b3SJacopo Mondi 	unsigned int width;
3125113d5b3SJacopo Mondi 	unsigned int height;
3135113d5b3SJacopo Mondi 
3145113d5b3SJacopo Mondi 	struct ov5640_timings dvp_timings;
3155113d5b3SJacopo Mondi 	struct ov5640_timings csi2_timings;
3165113d5b3SJacopo Mondi 
31719a81c14SSteve Longerbeam 	const struct reg_value *reg_data;
31819a81c14SSteve Longerbeam 	u32 reg_data_size;
3195113d5b3SJacopo Mondi 
3205113d5b3SJacopo Mondi 	/* Used by s_frame_interval only. */
3215554c80eSAdam Ford 	u32 max_fps;
32219f2e3e6SHugues Fruchet 	u32 def_fps;
32319a81c14SSteve Longerbeam };
32419a81c14SSteve Longerbeam 
32519a81c14SSteve Longerbeam struct ov5640_ctrls {
32619a81c14SSteve Longerbeam 	struct v4l2_ctrl_handler handler;
327cc196e48SBenoit Parrot 	struct v4l2_ctrl *pixel_rate;
3287a3b8d4bSJacopo Mondi 	struct v4l2_ctrl *link_freq;
32932979f67SJacopo Mondi 	struct v4l2_ctrl *hblank;
330bce93b82SJacopo Mondi 	struct v4l2_ctrl *vblank;
33119a81c14SSteve Longerbeam 	struct {
33219a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_exp;
33319a81c14SSteve Longerbeam 		struct v4l2_ctrl *exposure;
33419a81c14SSteve Longerbeam 	};
33519a81c14SSteve Longerbeam 	struct {
33619a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_wb;
33719a81c14SSteve Longerbeam 		struct v4l2_ctrl *blue_balance;
33819a81c14SSteve Longerbeam 		struct v4l2_ctrl *red_balance;
33919a81c14SSteve Longerbeam 	};
34019a81c14SSteve Longerbeam 	struct {
34119a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_gain;
34219a81c14SSteve Longerbeam 		struct v4l2_ctrl *gain;
34319a81c14SSteve Longerbeam 	};
34419a81c14SSteve Longerbeam 	struct v4l2_ctrl *brightness;
3451068fecaSMylène Josserand 	struct v4l2_ctrl *light_freq;
34619a81c14SSteve Longerbeam 	struct v4l2_ctrl *saturation;
34719a81c14SSteve Longerbeam 	struct v4l2_ctrl *contrast;
34819a81c14SSteve Longerbeam 	struct v4l2_ctrl *hue;
34919a81c14SSteve Longerbeam 	struct v4l2_ctrl *test_pattern;
350ce85705aSHugues Fruchet 	struct v4l2_ctrl *hflip;
351ce85705aSHugues Fruchet 	struct v4l2_ctrl *vflip;
35219a81c14SSteve Longerbeam };
35319a81c14SSteve Longerbeam 
35419a81c14SSteve Longerbeam struct ov5640_dev {
35519a81c14SSteve Longerbeam 	struct i2c_client *i2c_client;
35619a81c14SSteve Longerbeam 	struct v4l2_subdev sd;
35719a81c14SSteve Longerbeam 	struct media_pad pad;
35819a81c14SSteve Longerbeam 	struct v4l2_fwnode_endpoint ep; /* the parsed DT endpoint info */
35919a81c14SSteve Longerbeam 	struct clk *xclk; /* system clock to OV5640 */
36019a81c14SSteve Longerbeam 	u32 xclk_freq;
36119a81c14SSteve Longerbeam 
36219a81c14SSteve Longerbeam 	struct regulator_bulk_data supplies[OV5640_NUM_SUPPLIES];
36319a81c14SSteve Longerbeam 	struct gpio_desc *reset_gpio;
36419a81c14SSteve Longerbeam 	struct gpio_desc *pwdn_gpio;
365c3f3ba3eSHugues Fruchet 	bool   upside_down;
36619a81c14SSteve Longerbeam 
36719a81c14SSteve Longerbeam 	/* lock to protect all members below */
36819a81c14SSteve Longerbeam 	struct mutex lock;
36919a81c14SSteve Longerbeam 
37019a81c14SSteve Longerbeam 	int power_count;
37119a81c14SSteve Longerbeam 
37219a81c14SSteve Longerbeam 	struct v4l2_mbus_framefmt fmt;
373fb98e29fSHugues Fruchet 	bool pending_fmt_change;
37419a81c14SSteve Longerbeam 
37519a81c14SSteve Longerbeam 	const struct ov5640_mode_info *current_mode;
376985cdcb0SHugues Fruchet 	const struct ov5640_mode_info *last_mode;
37719a81c14SSteve Longerbeam 	enum ov5640_frame_rate current_fr;
37819a81c14SSteve Longerbeam 	struct v4l2_fract frame_interval;
3793c28588fSJacopo Mondi 	s64 current_link_freq;
38019a81c14SSteve Longerbeam 
38119a81c14SSteve Longerbeam 	struct ov5640_ctrls ctrls;
38219a81c14SSteve Longerbeam 
38319a81c14SSteve Longerbeam 	u32 prev_sysclk, prev_hts;
38419a81c14SSteve Longerbeam 	u32 ae_low, ae_high, ae_target;
38519a81c14SSteve Longerbeam 
38619a81c14SSteve Longerbeam 	bool pending_mode_change;
38719a81c14SSteve Longerbeam 	bool streaming;
38819a81c14SSteve Longerbeam };
38919a81c14SSteve Longerbeam 
39019a81c14SSteve Longerbeam static inline struct ov5640_dev *to_ov5640_dev(struct v4l2_subdev *sd)
39119a81c14SSteve Longerbeam {
39219a81c14SSteve Longerbeam 	return container_of(sd, struct ov5640_dev, sd);
39319a81c14SSteve Longerbeam }
39419a81c14SSteve Longerbeam 
39519a81c14SSteve Longerbeam static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
39619a81c14SSteve Longerbeam {
39719a81c14SSteve Longerbeam 	return &container_of(ctrl->handler, struct ov5640_dev,
39819a81c14SSteve Longerbeam 			     ctrls.handler)->sd;
39919a81c14SSteve Longerbeam }
40019a81c14SSteve Longerbeam 
4018e823f5cSJacopo Mondi static inline bool ov5640_is_csi2(const struct ov5640_dev *sensor)
4028e823f5cSJacopo Mondi {
4038e823f5cSJacopo Mondi 	return sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY;
4048e823f5cSJacopo Mondi }
4058e823f5cSJacopo Mondi 
40619a81c14SSteve Longerbeam /*
40719a81c14SSteve Longerbeam  * FIXME: all of these register tables are likely filled with
40819a81c14SSteve Longerbeam  * entries that set the register to their power-on default values,
40919a81c14SSteve Longerbeam  * and which are otherwise not touched by this driver. Those entries
41019a81c14SSteve Longerbeam  * should be identified and removed to speed register load time
41119a81c14SSteve Longerbeam  * over i2c.
41219a81c14SSteve Longerbeam  */
413fb98e29fSHugues Fruchet /* YUV422 UYVY VGA@30fps */
414*90b0f355SJacopo Mondi 
415*90b0f355SJacopo Mondi static const struct v4l2_mbus_framefmt ov5640_default_fmt = {
416*90b0f355SJacopo Mondi 	.code = MEDIA_BUS_FMT_UYVY8_2X8,
417*90b0f355SJacopo Mondi 	.width = 640,
418*90b0f355SJacopo Mondi 	.height = 480,
419*90b0f355SJacopo Mondi 	.colorspace = V4L2_COLORSPACE_SRGB,
420*90b0f355SJacopo Mondi 	.ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SRGB),
421*90b0f355SJacopo Mondi 	.quantization = V4L2_QUANTIZATION_FULL_RANGE,
422*90b0f355SJacopo Mondi 	.xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SRGB),
423*90b0f355SJacopo Mondi 	.field = V4L2_FIELD_NONE,
424*90b0f355SJacopo Mondi };
425*90b0f355SJacopo Mondi 
426e4359019SJacopo Mondi static const struct reg_value ov5640_init_setting[] = {
42719a81c14SSteve Longerbeam 	{0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0},
428576f5d4bSLad Prabhakar 	{0x3103, 0x03, 0, 0}, {0x3630, 0x36, 0, 0},
42919a81c14SSteve Longerbeam 	{0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0},
43019a81c14SSteve Longerbeam 	{0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0},
43119a81c14SSteve Longerbeam 	{0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0},
43219a81c14SSteve Longerbeam 	{0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, {0x3906, 0x10, 0, 0},
43319a81c14SSteve Longerbeam 	{0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, {0x3600, 0x08, 0, 0},
43419a81c14SSteve Longerbeam 	{0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, {0x3620, 0x52, 0, 0},
43519a81c14SSteve Longerbeam 	{0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, {0x3a13, 0x43, 0, 0},
43619a81c14SSteve Longerbeam 	{0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3635, 0x13, 0, 0},
43719a81c14SSteve Longerbeam 	{0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, {0x3622, 0x01, 0, 0},
43819a81c14SSteve Longerbeam 	{0x3c01, 0xa4, 0, 0}, {0x3c04, 0x28, 0, 0}, {0x3c05, 0x98, 0, 0},
43919a81c14SSteve Longerbeam 	{0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0},
44019a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
44119a81c14SSteve Longerbeam 	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
4423145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
44319a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
44419a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
44519a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
44619a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
44719a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
44819a81c14SSteve Longerbeam 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0},
44919a81c14SSteve Longerbeam 	{0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0},
450aa4bb8b8SJacopo Mondi 	{0x302e, 0x08, 0, 0}, {0x4300, 0x3f, 0, 0},
4512b5c18f9SChen-Yu Tsai 	{0x501f, 0x00, 0, 0}, {0x4407, 0x04, 0, 0},
45219a81c14SSteve Longerbeam 	{0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
453aa4bb8b8SJacopo Mondi 	{0x4837, 0x0a, 0, 0}, {0x3824, 0x02, 0, 0},
45419a81c14SSteve Longerbeam 	{0x5000, 0xa7, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0},
45519a81c14SSteve Longerbeam 	{0x5181, 0xf2, 0, 0}, {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0},
45619a81c14SSteve Longerbeam 	{0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0},
45719a81c14SSteve Longerbeam 	{0x5187, 0x09, 0, 0}, {0x5188, 0x09, 0, 0}, {0x5189, 0x88, 0, 0},
45819a81c14SSteve Longerbeam 	{0x518a, 0x54, 0, 0}, {0x518b, 0xee, 0, 0}, {0x518c, 0xb2, 0, 0},
45919a81c14SSteve Longerbeam 	{0x518d, 0x50, 0, 0}, {0x518e, 0x34, 0, 0}, {0x518f, 0x6b, 0, 0},
46019a81c14SSteve Longerbeam 	{0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0},
46119a81c14SSteve Longerbeam 	{0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0},
46219a81c14SSteve Longerbeam 	{0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0},
46319a81c14SSteve Longerbeam 	{0x5199, 0x6c, 0, 0}, {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0},
46419a81c14SSteve Longerbeam 	{0x519c, 0x09, 0, 0}, {0x519d, 0x2b, 0, 0}, {0x519e, 0x38, 0, 0},
46519a81c14SSteve Longerbeam 	{0x5381, 0x1e, 0, 0}, {0x5382, 0x5b, 0, 0}, {0x5383, 0x08, 0, 0},
46619a81c14SSteve Longerbeam 	{0x5384, 0x0a, 0, 0}, {0x5385, 0x7e, 0, 0}, {0x5386, 0x88, 0, 0},
46719a81c14SSteve Longerbeam 	{0x5387, 0x7c, 0, 0}, {0x5388, 0x6c, 0, 0}, {0x5389, 0x10, 0, 0},
46819a81c14SSteve Longerbeam 	{0x538a, 0x01, 0, 0}, {0x538b, 0x98, 0, 0}, {0x5300, 0x08, 0, 0},
46919a81c14SSteve Longerbeam 	{0x5301, 0x30, 0, 0}, {0x5302, 0x10, 0, 0}, {0x5303, 0x00, 0, 0},
47019a81c14SSteve Longerbeam 	{0x5304, 0x08, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x08, 0, 0},
47119a81c14SSteve Longerbeam 	{0x5307, 0x16, 0, 0}, {0x5309, 0x08, 0, 0}, {0x530a, 0x30, 0, 0},
47219a81c14SSteve Longerbeam 	{0x530b, 0x04, 0, 0}, {0x530c, 0x06, 0, 0}, {0x5480, 0x01, 0, 0},
47319a81c14SSteve Longerbeam 	{0x5481, 0x08, 0, 0}, {0x5482, 0x14, 0, 0}, {0x5483, 0x28, 0, 0},
47419a81c14SSteve Longerbeam 	{0x5484, 0x51, 0, 0}, {0x5485, 0x65, 0, 0}, {0x5486, 0x71, 0, 0},
47519a81c14SSteve Longerbeam 	{0x5487, 0x7d, 0, 0}, {0x5488, 0x87, 0, 0}, {0x5489, 0x91, 0, 0},
47619a81c14SSteve Longerbeam 	{0x548a, 0x9a, 0, 0}, {0x548b, 0xaa, 0, 0}, {0x548c, 0xb8, 0, 0},
47719a81c14SSteve Longerbeam 	{0x548d, 0xcd, 0, 0}, {0x548e, 0xdd, 0, 0}, {0x548f, 0xea, 0, 0},
47819a81c14SSteve Longerbeam 	{0x5490, 0x1d, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5583, 0x40, 0, 0},
47919a81c14SSteve Longerbeam 	{0x5584, 0x10, 0, 0}, {0x5589, 0x10, 0, 0}, {0x558a, 0x00, 0, 0},
48019a81c14SSteve Longerbeam 	{0x558b, 0xf8, 0, 0}, {0x5800, 0x23, 0, 0}, {0x5801, 0x14, 0, 0},
48119a81c14SSteve Longerbeam 	{0x5802, 0x0f, 0, 0}, {0x5803, 0x0f, 0, 0}, {0x5804, 0x12, 0, 0},
48219a81c14SSteve Longerbeam 	{0x5805, 0x26, 0, 0}, {0x5806, 0x0c, 0, 0}, {0x5807, 0x08, 0, 0},
48319a81c14SSteve Longerbeam 	{0x5808, 0x05, 0, 0}, {0x5809, 0x05, 0, 0}, {0x580a, 0x08, 0, 0},
48419a81c14SSteve Longerbeam 	{0x580b, 0x0d, 0, 0}, {0x580c, 0x08, 0, 0}, {0x580d, 0x03, 0, 0},
48519a81c14SSteve Longerbeam 	{0x580e, 0x00, 0, 0}, {0x580f, 0x00, 0, 0}, {0x5810, 0x03, 0, 0},
48619a81c14SSteve Longerbeam 	{0x5811, 0x09, 0, 0}, {0x5812, 0x07, 0, 0}, {0x5813, 0x03, 0, 0},
48719a81c14SSteve Longerbeam 	{0x5814, 0x00, 0, 0}, {0x5815, 0x01, 0, 0}, {0x5816, 0x03, 0, 0},
48819a81c14SSteve Longerbeam 	{0x5817, 0x08, 0, 0}, {0x5818, 0x0d, 0, 0}, {0x5819, 0x08, 0, 0},
48919a81c14SSteve Longerbeam 	{0x581a, 0x05, 0, 0}, {0x581b, 0x06, 0, 0}, {0x581c, 0x08, 0, 0},
49019a81c14SSteve Longerbeam 	{0x581d, 0x0e, 0, 0}, {0x581e, 0x29, 0, 0}, {0x581f, 0x17, 0, 0},
49119a81c14SSteve Longerbeam 	{0x5820, 0x11, 0, 0}, {0x5821, 0x11, 0, 0}, {0x5822, 0x15, 0, 0},
49219a81c14SSteve Longerbeam 	{0x5823, 0x28, 0, 0}, {0x5824, 0x46, 0, 0}, {0x5825, 0x26, 0, 0},
49319a81c14SSteve Longerbeam 	{0x5826, 0x08, 0, 0}, {0x5827, 0x26, 0, 0}, {0x5828, 0x64, 0, 0},
49419a81c14SSteve Longerbeam 	{0x5829, 0x26, 0, 0}, {0x582a, 0x24, 0, 0}, {0x582b, 0x22, 0, 0},
49519a81c14SSteve Longerbeam 	{0x582c, 0x24, 0, 0}, {0x582d, 0x24, 0, 0}, {0x582e, 0x06, 0, 0},
49619a81c14SSteve Longerbeam 	{0x582f, 0x22, 0, 0}, {0x5830, 0x40, 0, 0}, {0x5831, 0x42, 0, 0},
49719a81c14SSteve Longerbeam 	{0x5832, 0x24, 0, 0}, {0x5833, 0x26, 0, 0}, {0x5834, 0x24, 0, 0},
49819a81c14SSteve Longerbeam 	{0x5835, 0x22, 0, 0}, {0x5836, 0x22, 0, 0}, {0x5837, 0x26, 0, 0},
49919a81c14SSteve Longerbeam 	{0x5838, 0x44, 0, 0}, {0x5839, 0x24, 0, 0}, {0x583a, 0x26, 0, 0},
50019a81c14SSteve Longerbeam 	{0x583b, 0x28, 0, 0}, {0x583c, 0x42, 0, 0}, {0x583d, 0xce, 0, 0},
50119a81c14SSteve Longerbeam 	{0x5025, 0x00, 0, 0}, {0x3a0f, 0x30, 0, 0}, {0x3a10, 0x28, 0, 0},
50219a81c14SSteve Longerbeam 	{0x3a1b, 0x30, 0, 0}, {0x3a1e, 0x26, 0, 0}, {0x3a11, 0x60, 0, 0},
50319a81c14SSteve Longerbeam 	{0x3a1f, 0x14, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3c00, 0x04, 0, 300},
50419a81c14SSteve Longerbeam };
50519a81c14SSteve Longerbeam 
506db15c195SJacopo Mondi static const struct reg_value ov5640_setting_low_res[] = {
507c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
50819a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
509ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
5103145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
51119a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
51219a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
51319a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
51419a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
51519a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5162b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
517e15197bdSJacopo Mondi 	{0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0},
51819a81c14SSteve Longerbeam };
51919a81c14SSteve Longerbeam 
520086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_720P_1280_720[] = {
521c14d107eSMaxime Ripard 	{0x3c07, 0x07, 0, 0},
52219a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
523ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
5243145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
52519a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
52619a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0},
52719a81c14SSteve Longerbeam 	{0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0},
52819a81c14SSteve Longerbeam 	{0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0},
52919a81c14SSteve Longerbeam 	{0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0},
5302b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
53119a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
53219a81c14SSteve Longerbeam 	{0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0},
53319a81c14SSteve Longerbeam };
53419a81c14SSteve Longerbeam 
535086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_1080P_1920_1080[] = {
536c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
53719a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
538ce85705aSHugues Fruchet 	{0x3814, 0x11, 0, 0},
5393145efcdSJacopo Mondi 	{0x3815, 0x11, 0, 0},
54019a81c14SSteve Longerbeam 	{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
54119a81c14SSteve Longerbeam 	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
54219a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
54319a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
54419a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5452b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0},
54619a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
547c14d107eSMaxime Ripard 	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0},
548c14d107eSMaxime Ripard 	{0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0},
54919a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
550476dec01SMaxime Ripard 	{0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0},
55119a81c14SSteve Longerbeam 	{0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0},
55219a81c14SSteve Longerbeam 	{0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0},
55319a81c14SSteve Longerbeam 	{0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0},
5542b5c18f9SChen-Yu Tsai 	{0x3a15, 0x60, 0, 0}, {0x4407, 0x04, 0, 0},
55519a81c14SSteve Longerbeam 	{0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0},
55692b9096cSBenoit Parrot 	{0x4005, 0x1a, 0, 0},
55719a81c14SSteve Longerbeam };
55819a81c14SSteve Longerbeam 
559086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_QSXGA_2592_1944[] = {
560c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
56119a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
562ce85705aSHugues Fruchet 	{0x3814, 0x11, 0, 0},
5633145efcdSJacopo Mondi 	{0x3815, 0x11, 0, 0},
56419a81c14SSteve Longerbeam 	{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
56519a81c14SSteve Longerbeam 	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
56619a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
56719a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
56819a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5692b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0},
57019a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
57119a81c14SSteve Longerbeam 	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70},
57219a81c14SSteve Longerbeam };
57319a81c14SSteve Longerbeam 
5745113d5b3SJacopo Mondi static const struct ov5640_mode_info ov5640_mode_data[OV5640_NUM_MODES] = {
5758409d017SJacopo Mondi 	{
5768409d017SJacopo Mondi 		/* 160x120 */
5773145efcdSJacopo Mondi 		.id		= OV5640_MODE_QQVGA_160_120,
5783145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
5793145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
5805113d5b3SJacopo Mondi 		.width		= 160,
5815113d5b3SJacopo Mondi 		.height		= 120,
5825113d5b3SJacopo Mondi 		.dvp_timings = {
5833145efcdSJacopo Mondi 			.analog_crop = {
5843145efcdSJacopo Mondi 				.left	= 0,
5853145efcdSJacopo Mondi 				.top	= 4,
5863145efcdSJacopo Mondi 				.width	= 2624,
5873145efcdSJacopo Mondi 				.height	= 1944,
5883145efcdSJacopo Mondi 			},
5893145efcdSJacopo Mondi 			.crop = {
5903145efcdSJacopo Mondi 				.left	= 16,
5913145efcdSJacopo Mondi 				.top	= 6,
5923145efcdSJacopo Mondi 				.width	= 160,
5933145efcdSJacopo Mondi 				.height	= 120,
5943145efcdSJacopo Mondi 			},
5953145efcdSJacopo Mondi 			.htot		= 1896,
5963145efcdSJacopo Mondi 			.vblank_def	= 864,
5975113d5b3SJacopo Mondi 		},
5985113d5b3SJacopo Mondi 		.csi2_timings = {
5995113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
6005113d5b3SJacopo Mondi 			.analog_crop = {
6015113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
6025113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
6035113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
6045113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
6055113d5b3SJacopo Mondi 			},
6065113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
6075113d5b3SJacopo Mondi 			.crop = {
6085113d5b3SJacopo Mondi 				.left	= 2,
6095113d5b3SJacopo Mondi 				.top	= 4,
6105113d5b3SJacopo Mondi 				.width	= 160,
6115113d5b3SJacopo Mondi 				.height	= 120,
6125113d5b3SJacopo Mondi 			},
613961bed9fSJacopo Mondi 			.htot		= 1600,
614961bed9fSJacopo Mondi 			.vblank_def	= 878,
6155113d5b3SJacopo Mondi 		},
616db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
617db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
61819f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
61919f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
6208409d017SJacopo Mondi 	}, {
6218409d017SJacopo Mondi 		/* 176x144 */
6223145efcdSJacopo Mondi 		.id		= OV5640_MODE_QCIF_176_144,
6233145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
6243145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
6255113d5b3SJacopo Mondi 		.width		= 176,
6265113d5b3SJacopo Mondi 		.height		= 144,
6275113d5b3SJacopo Mondi 		.dvp_timings = {
6283145efcdSJacopo Mondi 			.analog_crop = {
6293145efcdSJacopo Mondi 				.left	= 0,
6303145efcdSJacopo Mondi 				.top	= 4,
6313145efcdSJacopo Mondi 				.width	= 2624,
6323145efcdSJacopo Mondi 				.height	= 1944,
6333145efcdSJacopo Mondi 			},
6343145efcdSJacopo Mondi 			.crop = {
6353145efcdSJacopo Mondi 				.left	= 16,
6363145efcdSJacopo Mondi 				.top	= 6,
6373145efcdSJacopo Mondi 				.width	= 176,
6383145efcdSJacopo Mondi 				.height	= 144,
6393145efcdSJacopo Mondi 			},
6403145efcdSJacopo Mondi 			.htot		= 1896,
6413145efcdSJacopo Mondi 			.vblank_def	= 840,
6425113d5b3SJacopo Mondi 		},
6435113d5b3SJacopo Mondi 		.csi2_timings = {
6445113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
6455113d5b3SJacopo Mondi 			.analog_crop = {
6465113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
6475113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
6485113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
6495113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
6505113d5b3SJacopo Mondi 			},
6515113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
6525113d5b3SJacopo Mondi 			.crop = {
6535113d5b3SJacopo Mondi 				.left	= 2,
6545113d5b3SJacopo Mondi 				.top	= 4,
6555113d5b3SJacopo Mondi 				.width	= 176,
6565113d5b3SJacopo Mondi 				.height	= 144,
6575113d5b3SJacopo Mondi 			},
658961bed9fSJacopo Mondi 			.htot		= 1600,
659961bed9fSJacopo Mondi 			.vblank_def	= 854,
6605113d5b3SJacopo Mondi 		},
661db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
662db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
66319f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
66419f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
6658409d017SJacopo Mondi 	}, {
6668409d017SJacopo Mondi 		/* 320x240 */
6673145efcdSJacopo Mondi 		.id		= OV5640_MODE_QVGA_320_240,
6683145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
6695113d5b3SJacopo Mondi 		.width		= 320,
6705113d5b3SJacopo Mondi 		.height		= 240,
6713145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
6725113d5b3SJacopo Mondi 		.dvp_timings = {
6733145efcdSJacopo Mondi 			.analog_crop = {
6743145efcdSJacopo Mondi 				.left	= 0,
6753145efcdSJacopo Mondi 				.top	= 4,
6763145efcdSJacopo Mondi 				.width	= 2624,
6773145efcdSJacopo Mondi 				.height	= 1944,
6783145efcdSJacopo Mondi 			},
6793145efcdSJacopo Mondi 			.crop = {
6803145efcdSJacopo Mondi 				.left	= 16,
6813145efcdSJacopo Mondi 				.top	= 6,
6823145efcdSJacopo Mondi 				.width	= 320,
6833145efcdSJacopo Mondi 				.height	= 240,
6843145efcdSJacopo Mondi 			},
6853145efcdSJacopo Mondi 			.htot		= 1896,
6863145efcdSJacopo Mondi 			.vblank_def	= 744,
6875113d5b3SJacopo Mondi 		},
6885113d5b3SJacopo Mondi 		.csi2_timings = {
6895113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
6905113d5b3SJacopo Mondi 			.analog_crop = {
6915113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
6925113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
6935113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
6945113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
6955113d5b3SJacopo Mondi 			},
6965113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
6975113d5b3SJacopo Mondi 			.crop = {
6985113d5b3SJacopo Mondi 				.left	= 2,
6995113d5b3SJacopo Mondi 				.top	= 4,
7005113d5b3SJacopo Mondi 				.width	= 320,
7015113d5b3SJacopo Mondi 				.height	= 240,
7025113d5b3SJacopo Mondi 			},
703961bed9fSJacopo Mondi 			.htot		= 1600,
704961bed9fSJacopo Mondi 			.vblank_def	= 760,
7055113d5b3SJacopo Mondi 		},
706db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
707db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
70819f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
70919f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
7108409d017SJacopo Mondi 	}, {
7118409d017SJacopo Mondi 		/* 640x480 */
7123145efcdSJacopo Mondi 		.id		= OV5640_MODE_VGA_640_480,
7133145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
7143145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
7155113d5b3SJacopo Mondi 		.width		= 640,
7165113d5b3SJacopo Mondi 		.height		= 480,
7175113d5b3SJacopo Mondi 		.dvp_timings = {
7183145efcdSJacopo Mondi 			.analog_crop = {
7193145efcdSJacopo Mondi 				.left	= 0,
7203145efcdSJacopo Mondi 				.top	= 4,
7213145efcdSJacopo Mondi 				.width	= 2624,
7223145efcdSJacopo Mondi 				.height	= 1944,
7233145efcdSJacopo Mondi 			},
7243145efcdSJacopo Mondi 			.crop = {
7253145efcdSJacopo Mondi 				.left	= 16,
7263145efcdSJacopo Mondi 				.top	= 6,
7273145efcdSJacopo Mondi 				.width	= 640,
7283145efcdSJacopo Mondi 				.height	= 480,
7293145efcdSJacopo Mondi 			},
7303145efcdSJacopo Mondi 			.htot		= 1896,
7313145efcdSJacopo Mondi 			.vblank_def	= 600,
7325113d5b3SJacopo Mondi 		},
7335113d5b3SJacopo Mondi 		.csi2_timings = {
7345113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
7355113d5b3SJacopo Mondi 			.analog_crop = {
7365113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
7375113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
7385113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
7395113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
7405113d5b3SJacopo Mondi 			},
7415113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
7425113d5b3SJacopo Mondi 			.crop = {
7435113d5b3SJacopo Mondi 				.left	= 2,
7445113d5b3SJacopo Mondi 				.top	= 4,
7455113d5b3SJacopo Mondi 				.width	= 640,
7465113d5b3SJacopo Mondi 				.height	= 480,
7475113d5b3SJacopo Mondi 			},
748961bed9fSJacopo Mondi 			.htot		= 1600,
749961bed9fSJacopo Mondi 			.vblank_def	= 520,
7505113d5b3SJacopo Mondi 		},
751db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
752db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
75319f2e3e6SHugues Fruchet 		.max_fps	= OV5640_60_FPS,
75419f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
7558409d017SJacopo Mondi 	}, {
7568409d017SJacopo Mondi 		/* 720x480 */
7573145efcdSJacopo Mondi 		.id		= OV5640_MODE_NTSC_720_480,
7583145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
7595113d5b3SJacopo Mondi 		.width		= 720,
7605113d5b3SJacopo Mondi 		.height		= 480,
7613145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
7625113d5b3SJacopo Mondi 		.dvp_timings = {
7633145efcdSJacopo Mondi 			.analog_crop = {
7643145efcdSJacopo Mondi 				.left	= 0,
7653145efcdSJacopo Mondi 				.top	= 4,
7663145efcdSJacopo Mondi 				.width	= 2624,
7673145efcdSJacopo Mondi 				.height	= 1944,
7683145efcdSJacopo Mondi 			},
7693145efcdSJacopo Mondi 			.crop = {
770e74ef55bSJacopo Mondi 				.left	= 56,
7713145efcdSJacopo Mondi 				.top	= 60,
7723145efcdSJacopo Mondi 				.width	= 720,
7733145efcdSJacopo Mondi 				.height	= 480,
7743145efcdSJacopo Mondi 			},
7753145efcdSJacopo Mondi 			.htot		= 1896,
7763145efcdSJacopo Mondi 			.vblank_def	= 504,
7775113d5b3SJacopo Mondi 		},
7785113d5b3SJacopo Mondi 		.csi2_timings = {
7795113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
7805113d5b3SJacopo Mondi 			.analog_crop = {
7815113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
7825113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
7835113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
7845113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
7855113d5b3SJacopo Mondi 			},
7865113d5b3SJacopo Mondi 			.crop = {
7875113d5b3SJacopo Mondi 				.left	= 56,
7885113d5b3SJacopo Mondi 				.top	= 60,
7895113d5b3SJacopo Mondi 				.width	= 720,
7905113d5b3SJacopo Mondi 				.height	= 480,
7915113d5b3SJacopo Mondi 			},
7925113d5b3SJacopo Mondi 			.htot		= 1896,
793961bed9fSJacopo Mondi 			.vblank_def	= 1206,
7945113d5b3SJacopo Mondi 		},
795db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
796db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
79719f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
79819f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
7998409d017SJacopo Mondi 	}, {
8008409d017SJacopo Mondi 		/* 720x576 */
8013145efcdSJacopo Mondi 		.id		= OV5640_MODE_PAL_720_576,
8023145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
8035113d5b3SJacopo Mondi 		.width		= 720,
8045113d5b3SJacopo Mondi 		.height		= 576,
8053145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
8065113d5b3SJacopo Mondi 		.dvp_timings = {
8073145efcdSJacopo Mondi 			.analog_crop = {
8083145efcdSJacopo Mondi 				.left	= 0,
8093145efcdSJacopo Mondi 				.top	= 4,
8103145efcdSJacopo Mondi 				.width	= 2624,
8113145efcdSJacopo Mondi 				.height	= 1944,
8123145efcdSJacopo Mondi 			},
8133145efcdSJacopo Mondi 			.crop = {
8143145efcdSJacopo Mondi 				.left	= 56,
8153145efcdSJacopo Mondi 				.top	= 6,
8163145efcdSJacopo Mondi 				.width	= 720,
8173145efcdSJacopo Mondi 				.height	= 576,
8183145efcdSJacopo Mondi 			},
8193145efcdSJacopo Mondi 			.htot		= 1896,
8203145efcdSJacopo Mondi 			.vblank_def	= 408,
8215113d5b3SJacopo Mondi 		},
8225113d5b3SJacopo Mondi 		.csi2_timings = {
8235113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
8245113d5b3SJacopo Mondi 			.analog_crop = {
8255113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
8265113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
8275113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
8285113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
8295113d5b3SJacopo Mondi 			},
8305113d5b3SJacopo Mondi 			.crop = {
8315113d5b3SJacopo Mondi 				.left	= 56,
8325113d5b3SJacopo Mondi 				.top	= 6,
8335113d5b3SJacopo Mondi 				.width	= 720,
8345113d5b3SJacopo Mondi 				.height	= 576,
8355113d5b3SJacopo Mondi 			},
8365113d5b3SJacopo Mondi 			.htot		= 1896,
837961bed9fSJacopo Mondi 			.vblank_def	= 1110,
8385113d5b3SJacopo Mondi 		},
839db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
840db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
84119f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
84219f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
8438409d017SJacopo Mondi 	}, {
8448409d017SJacopo Mondi 		/* 1024x768 */
8453145efcdSJacopo Mondi 		.id		= OV5640_MODE_XGA_1024_768,
8463145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
8473145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
8485113d5b3SJacopo Mondi 		.width		= 1024,
8495113d5b3SJacopo Mondi 		.height		= 768,
8505113d5b3SJacopo Mondi 		.dvp_timings = {
8513145efcdSJacopo Mondi 			.analog_crop = {
8523145efcdSJacopo Mondi 				.left	= 0,
8533145efcdSJacopo Mondi 				.top	= 4,
8543145efcdSJacopo Mondi 				.width	= 2624,
8553145efcdSJacopo Mondi 				.height	= 1944,
8563145efcdSJacopo Mondi 			},
8573145efcdSJacopo Mondi 			.crop = {
8583145efcdSJacopo Mondi 				.left	= 16,
8593145efcdSJacopo Mondi 				.top	= 6,
8603145efcdSJacopo Mondi 				.width	= 1024,
8613145efcdSJacopo Mondi 				.height	= 768,
8623145efcdSJacopo Mondi 			},
8633145efcdSJacopo Mondi 			.htot		= 1896,
8643145efcdSJacopo Mondi 			.vblank_def	= 312,
8655113d5b3SJacopo Mondi 		},
8665113d5b3SJacopo Mondi 		.csi2_timings = {
8675113d5b3SJacopo Mondi 			.analog_crop = {
8685113d5b3SJacopo Mondi 				.left	= 0,
8695113d5b3SJacopo Mondi 				.top	= 4,
8705113d5b3SJacopo Mondi 				.width	= OV5640_NATIVE_WIDTH,
8715113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
8725113d5b3SJacopo Mondi 			},
8735113d5b3SJacopo Mondi 			.crop = {
8745113d5b3SJacopo Mondi 				.left	= 16,
8755113d5b3SJacopo Mondi 				.top	= 6,
8765113d5b3SJacopo Mondi 				.width	= 1024,
8775113d5b3SJacopo Mondi 				.height	= 768,
8785113d5b3SJacopo Mondi 			},
8795113d5b3SJacopo Mondi 			.htot		= 1896,
880961bed9fSJacopo Mondi 			.vblank_def	= 918,
8815113d5b3SJacopo Mondi 		},
882db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
883db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
88419f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
88519f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
8868409d017SJacopo Mondi 	}, {
8878409d017SJacopo Mondi 		/* 1280x720 */
8883145efcdSJacopo Mondi 		.id		= OV5640_MODE_720P_1280_720,
8893145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
8903145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_124M,
8915113d5b3SJacopo Mondi 		.width		= 1280,
8925113d5b3SJacopo Mondi 		.height		= 720,
8935113d5b3SJacopo Mondi 		.dvp_timings = {
8943145efcdSJacopo Mondi 			.analog_crop = {
8953145efcdSJacopo Mondi 				.left	= 0,
8963145efcdSJacopo Mondi 				.top	= 250,
8973145efcdSJacopo Mondi 				.width	= 2624,
8983145efcdSJacopo Mondi 				.height	= 1456,
8993145efcdSJacopo Mondi 			},
9003145efcdSJacopo Mondi 			.crop = {
9013145efcdSJacopo Mondi 				.left	= 16,
9023145efcdSJacopo Mondi 				.top	= 4,
9033145efcdSJacopo Mondi 				.width	= 1280,
9043145efcdSJacopo Mondi 				.height	= 720,
9053145efcdSJacopo Mondi 			},
9063145efcdSJacopo Mondi 			.htot		= 1892,
9073145efcdSJacopo Mondi 			.vblank_def	= 20,
9085113d5b3SJacopo Mondi 		},
9095113d5b3SJacopo Mondi 		.csi2_timings = {
9105113d5b3SJacopo Mondi 			.analog_crop = {
9115113d5b3SJacopo Mondi 				.left	= 0,
9125113d5b3SJacopo Mondi 				.top	= 250,
9135113d5b3SJacopo Mondi 				.width	= 2624,
9145113d5b3SJacopo Mondi 				.height	= 1456,
9155113d5b3SJacopo Mondi 			},
9165113d5b3SJacopo Mondi 			.crop = {
9175113d5b3SJacopo Mondi 				.left	= 16,
9185113d5b3SJacopo Mondi 				.top	= 4,
9195113d5b3SJacopo Mondi 				.width	= 1280,
9205113d5b3SJacopo Mondi 				.height	= 720,
9215113d5b3SJacopo Mondi 			},
922961bed9fSJacopo Mondi 			.htot		= 1600,
923961bed9fSJacopo Mondi 			.vblank_def	= 560,
9245113d5b3SJacopo Mondi 		},
9253145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_720P_1280_720,
9263145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_720P_1280_720),
92719f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
92819f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
9298409d017SJacopo Mondi 	}, {
9308409d017SJacopo Mondi 		/* 1920x1080 */
9313145efcdSJacopo Mondi 		.id		= OV5640_MODE_1080P_1920_1080,
9323145efcdSJacopo Mondi 		.dn_mode	= SCALING,
9333145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_148M,
9345113d5b3SJacopo Mondi 		.width		= 1920,
9355113d5b3SJacopo Mondi 		.height		= 1080,
9365113d5b3SJacopo Mondi 		.dvp_timings = {
9373145efcdSJacopo Mondi 			.analog_crop = {
9383145efcdSJacopo Mondi 				.left	= 336,
9393145efcdSJacopo Mondi 				.top	= 434,
9403145efcdSJacopo Mondi 				.width	= 1952,
9413145efcdSJacopo Mondi 				.height	= 1088,
9423145efcdSJacopo Mondi 			},
9433145efcdSJacopo Mondi 			.crop = {
9443145efcdSJacopo Mondi 				.left	= 16,
9453145efcdSJacopo Mondi 				.top	= 4,
9463145efcdSJacopo Mondi 				.width	= 1920,
9473145efcdSJacopo Mondi 				.height	= 1080,
9483145efcdSJacopo Mondi 			},
9493145efcdSJacopo Mondi 			.htot		= 2500,
9503145efcdSJacopo Mondi 			.vblank_def	= 40,
9515113d5b3SJacopo Mondi 		},
9525113d5b3SJacopo Mondi 		.csi2_timings = {
9535113d5b3SJacopo Mondi 			/* Crop the full valid pixel array in the center. */
9545113d5b3SJacopo Mondi 			.analog_crop = {
9555113d5b3SJacopo Mondi 				.left	= 336,
9565113d5b3SJacopo Mondi 				.top	= 434,
9575113d5b3SJacopo Mondi 				.width	= 1952,
9585113d5b3SJacopo Mondi 				.height	= 1088,
9595113d5b3SJacopo Mondi 			},
9605113d5b3SJacopo Mondi 			/* Maintain a larger processing margins. */
9615113d5b3SJacopo Mondi 			.crop = {
9625113d5b3SJacopo Mondi 				.left	= 16,
9635113d5b3SJacopo Mondi 				.top	= 4,
9645113d5b3SJacopo Mondi 				.width	= 1920,
9655113d5b3SJacopo Mondi 				.height	= 1080,
9665113d5b3SJacopo Mondi 			},
967961bed9fSJacopo Mondi 			.htot		= 2234,
968961bed9fSJacopo Mondi 			.vblank_def	= 24,
9695113d5b3SJacopo Mondi 		},
9703145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_1080P_1920_1080,
9713145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_1080P_1920_1080),
97219f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
97319f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
9748409d017SJacopo Mondi 	}, {
9758409d017SJacopo Mondi 		/* 2592x1944 */
9763145efcdSJacopo Mondi 		.id		= OV5640_MODE_QSXGA_2592_1944,
9773145efcdSJacopo Mondi 		.dn_mode	= SCALING,
9783145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_168M,
9795113d5b3SJacopo Mondi 		.width		= OV5640_PIXEL_ARRAY_WIDTH,
9805113d5b3SJacopo Mondi 		.height		= OV5640_PIXEL_ARRAY_HEIGHT,
9815113d5b3SJacopo Mondi 		.dvp_timings = {
9823145efcdSJacopo Mondi 			.analog_crop = {
9833145efcdSJacopo Mondi 				.left	= 0,
9843145efcdSJacopo Mondi 				.top	= 0,
9853145efcdSJacopo Mondi 				.width	= 2624,
9863145efcdSJacopo Mondi 				.height	= 1952,
9873145efcdSJacopo Mondi 			},
9883145efcdSJacopo Mondi 			.crop = {
9893145efcdSJacopo Mondi 				.left	= 16,
9903145efcdSJacopo Mondi 				.top	= 4,
9913145efcdSJacopo Mondi 				.width	= 2592,
9923145efcdSJacopo Mondi 				.height	= 1944,
9933145efcdSJacopo Mondi 			},
9943145efcdSJacopo Mondi 			.htot		= 2844,
9953145efcdSJacopo Mondi 			.vblank_def	= 24,
9965113d5b3SJacopo Mondi 		},
9975113d5b3SJacopo Mondi 		.csi2_timings = {
9985113d5b3SJacopo Mondi 			/* Give more processing margin to full resolution. */
9995113d5b3SJacopo Mondi 			.analog_crop = {
10005113d5b3SJacopo Mondi 				.left	= 0,
10015113d5b3SJacopo Mondi 				.top	= 0,
10025113d5b3SJacopo Mondi 				.width	= OV5640_NATIVE_WIDTH,
10035113d5b3SJacopo Mondi 				.height	= 1952,
10045113d5b3SJacopo Mondi 			},
10055113d5b3SJacopo Mondi 			.crop = {
10065113d5b3SJacopo Mondi 				.left	= 16,
10075113d5b3SJacopo Mondi 				.top	= 4,
10085113d5b3SJacopo Mondi 				.width	= 2592,
10095113d5b3SJacopo Mondi 				.height	= 1944,
10105113d5b3SJacopo Mondi 			},
10115113d5b3SJacopo Mondi 			.htot		= 2844,
10125113d5b3SJacopo Mondi 			.vblank_def	= 24,
10135113d5b3SJacopo Mondi 		},
10143145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_QSXGA_2592_1944,
10153145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_QSXGA_2592_1944),
101619f2e3e6SHugues Fruchet 		.max_fps	= OV5640_15_FPS,
101719f2e3e6SHugues Fruchet 		.def_fps	= OV5640_15_FPS
10188409d017SJacopo Mondi 	},
101919a81c14SSteve Longerbeam };
102019a81c14SSteve Longerbeam 
10212de6bb97SJacopo Mondi static const struct ov5640_timings *
10222de6bb97SJacopo Mondi ov5640_timings(const struct ov5640_dev *sensor,
10232de6bb97SJacopo Mondi 	       const struct ov5640_mode_info *mode)
10242de6bb97SJacopo Mondi {
10252de6bb97SJacopo Mondi 	if (ov5640_is_csi2(sensor))
10262de6bb97SJacopo Mondi 		return &mode->csi2_timings;
10272de6bb97SJacopo Mondi 
10282de6bb97SJacopo Mondi 	return &mode->dvp_timings;
10292de6bb97SJacopo Mondi }
10302de6bb97SJacopo Mondi 
103119a81c14SSteve Longerbeam static int ov5640_init_slave_id(struct ov5640_dev *sensor)
103219a81c14SSteve Longerbeam {
103319a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
103419a81c14SSteve Longerbeam 	struct i2c_msg msg;
103519a81c14SSteve Longerbeam 	u8 buf[3];
103619a81c14SSteve Longerbeam 	int ret;
103719a81c14SSteve Longerbeam 
103819a81c14SSteve Longerbeam 	if (client->addr == OV5640_DEFAULT_SLAVE_ID)
103919a81c14SSteve Longerbeam 		return 0;
104019a81c14SSteve Longerbeam 
104119a81c14SSteve Longerbeam 	buf[0] = OV5640_REG_SLAVE_ID >> 8;
104219a81c14SSteve Longerbeam 	buf[1] = OV5640_REG_SLAVE_ID & 0xff;
104319a81c14SSteve Longerbeam 	buf[2] = client->addr << 1;
104419a81c14SSteve Longerbeam 
104519a81c14SSteve Longerbeam 	msg.addr = OV5640_DEFAULT_SLAVE_ID;
104619a81c14SSteve Longerbeam 	msg.flags = 0;
104719a81c14SSteve Longerbeam 	msg.buf = buf;
104819a81c14SSteve Longerbeam 	msg.len = sizeof(buf);
104919a81c14SSteve Longerbeam 
105019a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, &msg, 1);
105119a81c14SSteve Longerbeam 	if (ret < 0) {
105219a81c14SSteve Longerbeam 		dev_err(&client->dev, "%s: failed with %d\n", __func__, ret);
105319a81c14SSteve Longerbeam 		return ret;
105419a81c14SSteve Longerbeam 	}
105519a81c14SSteve Longerbeam 
105619a81c14SSteve Longerbeam 	return 0;
105719a81c14SSteve Longerbeam }
105819a81c14SSteve Longerbeam 
105919a81c14SSteve Longerbeam static int ov5640_write_reg(struct ov5640_dev *sensor, u16 reg, u8 val)
106019a81c14SSteve Longerbeam {
106119a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
106219a81c14SSteve Longerbeam 	struct i2c_msg msg;
106319a81c14SSteve Longerbeam 	u8 buf[3];
106419a81c14SSteve Longerbeam 	int ret;
106519a81c14SSteve Longerbeam 
106619a81c14SSteve Longerbeam 	buf[0] = reg >> 8;
106719a81c14SSteve Longerbeam 	buf[1] = reg & 0xff;
106819a81c14SSteve Longerbeam 	buf[2] = val;
106919a81c14SSteve Longerbeam 
107019a81c14SSteve Longerbeam 	msg.addr = client->addr;
107119a81c14SSteve Longerbeam 	msg.flags = client->flags;
107219a81c14SSteve Longerbeam 	msg.buf = buf;
107319a81c14SSteve Longerbeam 	msg.len = sizeof(buf);
107419a81c14SSteve Longerbeam 
107519a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, &msg, 1);
107619a81c14SSteve Longerbeam 	if (ret < 0) {
10773924c623SHugues Fruchet 		dev_err(&client->dev, "%s: error: reg=%x, val=%x\n",
107819a81c14SSteve Longerbeam 			__func__, reg, val);
107919a81c14SSteve Longerbeam 		return ret;
108019a81c14SSteve Longerbeam 	}
108119a81c14SSteve Longerbeam 
108219a81c14SSteve Longerbeam 	return 0;
108319a81c14SSteve Longerbeam }
108419a81c14SSteve Longerbeam 
108519a81c14SSteve Longerbeam static int ov5640_read_reg(struct ov5640_dev *sensor, u16 reg, u8 *val)
108619a81c14SSteve Longerbeam {
108719a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
108819a81c14SSteve Longerbeam 	struct i2c_msg msg[2];
108919a81c14SSteve Longerbeam 	u8 buf[2];
109019a81c14SSteve Longerbeam 	int ret;
109119a81c14SSteve Longerbeam 
109219a81c14SSteve Longerbeam 	buf[0] = reg >> 8;
109319a81c14SSteve Longerbeam 	buf[1] = reg & 0xff;
109419a81c14SSteve Longerbeam 
109519a81c14SSteve Longerbeam 	msg[0].addr = client->addr;
109619a81c14SSteve Longerbeam 	msg[0].flags = client->flags;
109719a81c14SSteve Longerbeam 	msg[0].buf = buf;
109819a81c14SSteve Longerbeam 	msg[0].len = sizeof(buf);
109919a81c14SSteve Longerbeam 
110019a81c14SSteve Longerbeam 	msg[1].addr = client->addr;
110119a81c14SSteve Longerbeam 	msg[1].flags = client->flags | I2C_M_RD;
110219a81c14SSteve Longerbeam 	msg[1].buf = buf;
110319a81c14SSteve Longerbeam 	msg[1].len = 1;
110419a81c14SSteve Longerbeam 
110519a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, msg, 2);
11063924c623SHugues Fruchet 	if (ret < 0) {
11073924c623SHugues Fruchet 		dev_err(&client->dev, "%s: error: reg=%x\n",
11083924c623SHugues Fruchet 			__func__, reg);
110919a81c14SSteve Longerbeam 		return ret;
11103924c623SHugues Fruchet 	}
111119a81c14SSteve Longerbeam 
111219a81c14SSteve Longerbeam 	*val = buf[0];
111319a81c14SSteve Longerbeam 	return 0;
111419a81c14SSteve Longerbeam }
111519a81c14SSteve Longerbeam 
111619a81c14SSteve Longerbeam static int ov5640_read_reg16(struct ov5640_dev *sensor, u16 reg, u16 *val)
111719a81c14SSteve Longerbeam {
111819a81c14SSteve Longerbeam 	u8 hi, lo;
111919a81c14SSteve Longerbeam 	int ret;
112019a81c14SSteve Longerbeam 
112119a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg, &hi);
112219a81c14SSteve Longerbeam 	if (ret)
112319a81c14SSteve Longerbeam 		return ret;
112419a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg + 1, &lo);
112519a81c14SSteve Longerbeam 	if (ret)
112619a81c14SSteve Longerbeam 		return ret;
112719a81c14SSteve Longerbeam 
112819a81c14SSteve Longerbeam 	*val = ((u16)hi << 8) | (u16)lo;
112919a81c14SSteve Longerbeam 	return 0;
113019a81c14SSteve Longerbeam }
113119a81c14SSteve Longerbeam 
113219a81c14SSteve Longerbeam static int ov5640_write_reg16(struct ov5640_dev *sensor, u16 reg, u16 val)
113319a81c14SSteve Longerbeam {
113419a81c14SSteve Longerbeam 	int ret;
113519a81c14SSteve Longerbeam 
113619a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, reg, val >> 8);
113719a81c14SSteve Longerbeam 	if (ret)
113819a81c14SSteve Longerbeam 		return ret;
113919a81c14SSteve Longerbeam 
114019a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, reg + 1, val & 0xff);
114119a81c14SSteve Longerbeam }
114219a81c14SSteve Longerbeam 
114319a81c14SSteve Longerbeam static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg,
114419a81c14SSteve Longerbeam 			  u8 mask, u8 val)
114519a81c14SSteve Longerbeam {
114619a81c14SSteve Longerbeam 	u8 readval;
114719a81c14SSteve Longerbeam 	int ret;
114819a81c14SSteve Longerbeam 
114919a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg, &readval);
115019a81c14SSteve Longerbeam 	if (ret)
115119a81c14SSteve Longerbeam 		return ret;
115219a81c14SSteve Longerbeam 
115319a81c14SSteve Longerbeam 	readval &= ~mask;
115419a81c14SSteve Longerbeam 	val &= mask;
115519a81c14SSteve Longerbeam 	val |= readval;
115619a81c14SSteve Longerbeam 
115719a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, reg, val);
115819a81c14SSteve Longerbeam }
115919a81c14SSteve Longerbeam 
1160aa288248SMaxime Ripard /*
1161aa288248SMaxime Ripard  * After trying the various combinations, reading various
1162f8a7647dSMauro Carvalho Chehab  * documentations spread around the net, and from the various
1163aa288248SMaxime Ripard  * feedback, the clock tree is probably as follows:
1164aa288248SMaxime Ripard  *
1165aa288248SMaxime Ripard  *   +--------------+
1166aa288248SMaxime Ripard  *   |  Ext. Clock  |
1167aa288248SMaxime Ripard  *   +-+------------+
1168aa288248SMaxime Ripard  *     |  +----------+
1169aa288248SMaxime Ripard  *     +->|   PLL1   | - reg 0x3036, for the multiplier
1170aa288248SMaxime Ripard  *        +-+--------+ - reg 0x3037, bits 0-3 for the pre-divider
1171aa288248SMaxime Ripard  *          |  +--------------+
1172aa288248SMaxime Ripard  *          +->| System Clock |  - reg 0x3035, bits 4-7
1173aa288248SMaxime Ripard  *             +-+------------+
1174aa288248SMaxime Ripard  *               |  +--------------+
1175aa288248SMaxime Ripard  *               +->| MIPI Divider | - reg 0x3035, bits 0-3
1176aa288248SMaxime Ripard  *               |  +-+------------+
1177aa288248SMaxime Ripard  *               |    +----------------> MIPI SCLK
1178aa288248SMaxime Ripard  *               |    +  +-----+
1179aa288248SMaxime Ripard  *               |    +->| / 2 |-------> MIPI BIT CLK
1180aa288248SMaxime Ripard  *               |       +-----+
1181aa288248SMaxime Ripard  *               |  +--------------+
1182aa288248SMaxime Ripard  *               +->| PLL Root Div | - reg 0x3037, bit 4
1183aa288248SMaxime Ripard  *                  +-+------------+
1184aa288248SMaxime Ripard  *                    |  +---------+
11854c85f628SPaul Kocialkowski  *                    +->| Bit Div | - reg 0x3034, bits 0-3
1186aa288248SMaxime Ripard  *                       +-+-------+
1187aa288248SMaxime Ripard  *                         |  +-------------+
1188aa288248SMaxime Ripard  *                         +->| SCLK Div    | - reg 0x3108, bits 0-1
1189aa288248SMaxime Ripard  *                         |  +-+-----------+
1190aa288248SMaxime Ripard  *                         |    +---------------> SCLK
1191aa288248SMaxime Ripard  *                         |  +-------------+
1192aa288248SMaxime Ripard  *                         +->| SCLK 2X Div | - reg 0x3108, bits 2-3
1193aa288248SMaxime Ripard  *                         |  +-+-----------+
1194aa288248SMaxime Ripard  *                         |    +---------------> SCLK 2X
1195aa288248SMaxime Ripard  *                         |  +-------------+
1196aa288248SMaxime Ripard  *                         +->| PCLK Div    | - reg 0x3108, bits 4-5
1197aa288248SMaxime Ripard  *                            ++------------+
1198aa288248SMaxime Ripard  *                             +  +-----------+
1199aa288248SMaxime Ripard  *                             +->|   P_DIV   | - reg 0x3035, bits 0-3
1200aa288248SMaxime Ripard  *                                +-----+-----+
1201aa288248SMaxime Ripard  *                                       +------------> PCLK
1202aa288248SMaxime Ripard  *
12036c957ed7SJacopo Mondi  * There seems to be also constraints:
1204aa288248SMaxime Ripard  *  - the PLL pre-divider output rate should be in the 4-27MHz range
1205aa288248SMaxime Ripard  *  - the PLL multiplier output rate should be in the 500-1000MHz range
1206aa288248SMaxime Ripard  *  - PCLK >= SCLK * 2 in YUV, >= SCLK in Raw or JPEG
1207aa288248SMaxime Ripard  */
1208aa288248SMaxime Ripard 
1209aa288248SMaxime Ripard /*
1210aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1211aa288248SMaxime Ripard  * set to 3 in the vendor kernels.
1212aa288248SMaxime Ripard  */
1213aa288248SMaxime Ripard #define OV5640_PLL_PREDIV	3
1214aa288248SMaxime Ripard 
1215aa288248SMaxime Ripard #define OV5640_PLL_MULT_MIN	4
1216aa288248SMaxime Ripard #define OV5640_PLL_MULT_MAX	252
1217aa288248SMaxime Ripard 
1218aa288248SMaxime Ripard /*
1219aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 16, but the value is
1220aa288248SMaxime Ripard  * always set to either 1 or 2 in the vendor kernels.
1221aa288248SMaxime Ripard  */
1222aa288248SMaxime Ripard #define OV5640_SYSDIV_MIN	1
1223aa288248SMaxime Ripard #define OV5640_SYSDIV_MAX	16
1224aa288248SMaxime Ripard 
1225aa288248SMaxime Ripard /*
1226aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 2, but the value is always
1227aa288248SMaxime Ripard  * set to 2 in the vendor kernels.
1228aa288248SMaxime Ripard  */
1229aa288248SMaxime Ripard #define OV5640_PLL_ROOT_DIV			2
1230aa288248SMaxime Ripard #define OV5640_PLL_CTRL3_PLL_ROOT_DIV_2		BIT(4)
1231aa288248SMaxime Ripard 
1232aa288248SMaxime Ripard /*
1233aa288248SMaxime Ripard  * We only supports 8-bit formats at the moment
1234aa288248SMaxime Ripard  */
1235aa288248SMaxime Ripard #define OV5640_BIT_DIV				2
1236aa288248SMaxime Ripard #define OV5640_PLL_CTRL0_MIPI_MODE_8BIT		0x08
1237aa288248SMaxime Ripard 
1238aa288248SMaxime Ripard /*
1239aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1240aa288248SMaxime Ripard  * set to 2 in the vendor kernels.
1241aa288248SMaxime Ripard  */
1242aa288248SMaxime Ripard #define OV5640_SCLK_ROOT_DIV	2
1243aa288248SMaxime Ripard 
1244aa288248SMaxime Ripard /*
1245aa288248SMaxime Ripard  * This is hardcoded so that the consistency is maintained between SCLK and
1246aa288248SMaxime Ripard  * SCLK 2x.
1247aa288248SMaxime Ripard  */
1248aa288248SMaxime Ripard #define OV5640_SCLK2X_ROOT_DIV (OV5640_SCLK_ROOT_DIV / 2)
1249aa288248SMaxime Ripard 
1250aa288248SMaxime Ripard /*
1251aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1252aa288248SMaxime Ripard  * set to 1 in the vendor kernels.
1253aa288248SMaxime Ripard  */
1254aa288248SMaxime Ripard #define OV5640_PCLK_ROOT_DIV			1
1255aa288248SMaxime Ripard #define OV5640_PLL_SYS_ROOT_DIVIDER_BYPASS	0x00
1256aa288248SMaxime Ripard 
1257aa288248SMaxime Ripard static unsigned long ov5640_compute_sys_clk(struct ov5640_dev *sensor,
1258aa288248SMaxime Ripard 					    u8 pll_prediv, u8 pll_mult,
1259aa288248SMaxime Ripard 					    u8 sysdiv)
1260aa288248SMaxime Ripard {
1261aa288248SMaxime Ripard 	unsigned long sysclk = sensor->xclk_freq / pll_prediv * pll_mult;
1262aa288248SMaxime Ripard 
1263aa288248SMaxime Ripard 	/* PLL1 output cannot exceed 1GHz. */
1264aa288248SMaxime Ripard 	if (sysclk / 1000000 > 1000)
1265aa288248SMaxime Ripard 		return 0;
1266aa288248SMaxime Ripard 
1267aa288248SMaxime Ripard 	return sysclk / sysdiv;
1268aa288248SMaxime Ripard }
1269aa288248SMaxime Ripard 
1270aa288248SMaxime Ripard static unsigned long ov5640_calc_sys_clk(struct ov5640_dev *sensor,
1271aa288248SMaxime Ripard 					 unsigned long rate,
1272aa288248SMaxime Ripard 					 u8 *pll_prediv, u8 *pll_mult,
1273aa288248SMaxime Ripard 					 u8 *sysdiv)
1274aa288248SMaxime Ripard {
1275aa288248SMaxime Ripard 	unsigned long best = ~0;
1276aa288248SMaxime Ripard 	u8 best_sysdiv = 1, best_mult = 1;
1277aa288248SMaxime Ripard 	u8 _sysdiv, _pll_mult;
1278aa288248SMaxime Ripard 
1279aa288248SMaxime Ripard 	for (_sysdiv = OV5640_SYSDIV_MIN;
1280aa288248SMaxime Ripard 	     _sysdiv <= OV5640_SYSDIV_MAX;
1281aa288248SMaxime Ripard 	     _sysdiv++) {
1282aa288248SMaxime Ripard 		for (_pll_mult = OV5640_PLL_MULT_MIN;
1283aa288248SMaxime Ripard 		     _pll_mult <= OV5640_PLL_MULT_MAX;
1284aa288248SMaxime Ripard 		     _pll_mult++) {
1285aa288248SMaxime Ripard 			unsigned long _rate;
1286aa288248SMaxime Ripard 
1287aa288248SMaxime Ripard 			/*
1288aa288248SMaxime Ripard 			 * The PLL multiplier cannot be odd if above
1289aa288248SMaxime Ripard 			 * 127.
1290aa288248SMaxime Ripard 			 */
1291aa288248SMaxime Ripard 			if (_pll_mult > 127 && (_pll_mult % 2))
1292aa288248SMaxime Ripard 				continue;
1293aa288248SMaxime Ripard 
1294aa288248SMaxime Ripard 			_rate = ov5640_compute_sys_clk(sensor,
1295aa288248SMaxime Ripard 						       OV5640_PLL_PREDIV,
1296aa288248SMaxime Ripard 						       _pll_mult, _sysdiv);
1297aa288248SMaxime Ripard 
1298aa288248SMaxime Ripard 			/*
1299aa288248SMaxime Ripard 			 * We have reached the maximum allowed PLL1 output,
1300aa288248SMaxime Ripard 			 * increase sysdiv.
1301aa288248SMaxime Ripard 			 */
13022e3df204SAdam Ford 			if (!_rate)
1303aa288248SMaxime Ripard 				break;
1304aa288248SMaxime Ripard 
1305aa288248SMaxime Ripard 			/*
1306aa288248SMaxime Ripard 			 * Prefer rates above the expected clock rate than
1307aa288248SMaxime Ripard 			 * below, even if that means being less precise.
1308aa288248SMaxime Ripard 			 */
1309aa288248SMaxime Ripard 			if (_rate < rate)
1310aa288248SMaxime Ripard 				continue;
1311aa288248SMaxime Ripard 
1312aa288248SMaxime Ripard 			if (abs(rate - _rate) < abs(rate - best)) {
1313aa288248SMaxime Ripard 				best = _rate;
1314aa288248SMaxime Ripard 				best_sysdiv = _sysdiv;
1315aa288248SMaxime Ripard 				best_mult = _pll_mult;
1316aa288248SMaxime Ripard 			}
1317aa288248SMaxime Ripard 
1318aa288248SMaxime Ripard 			if (_rate == rate)
1319aa288248SMaxime Ripard 				goto out;
1320aa288248SMaxime Ripard 		}
1321aa288248SMaxime Ripard 	}
1322aa288248SMaxime Ripard 
1323aa288248SMaxime Ripard out:
1324aa288248SMaxime Ripard 	*sysdiv = best_sysdiv;
1325aa288248SMaxime Ripard 	*pll_prediv = OV5640_PLL_PREDIV;
1326aa288248SMaxime Ripard 	*pll_mult = best_mult;
1327aa288248SMaxime Ripard 
1328aa288248SMaxime Ripard 	return best;
1329aa288248SMaxime Ripard }
1330aa288248SMaxime Ripard 
1331aa288248SMaxime Ripard /*
1332aa288248SMaxime Ripard  * ov5640_set_mipi_pclk() - Calculate the clock tree configuration values
1333aa288248SMaxime Ripard  *			    for the MIPI CSI-2 output.
1334aa288248SMaxime Ripard  */
13356c957ed7SJacopo Mondi static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor)
1336aa288248SMaxime Ripard {
13376c957ed7SJacopo Mondi 	u8 bit_div, mipi_div, pclk_div, sclk_div, sclk2x_div, root_div;
1338aa288248SMaxime Ripard 	u8 prediv, mult, sysdiv;
13396c957ed7SJacopo Mondi 	unsigned long link_freq;
13406c957ed7SJacopo Mondi 	unsigned long sysclk;
13416c957ed7SJacopo Mondi 	u8 pclk_period;
13426c957ed7SJacopo Mondi 	u32 sample_rate;
13436c957ed7SJacopo Mondi 	u32 num_lanes;
1344aa288248SMaxime Ripard 	int ret;
1345aa288248SMaxime Ripard 
13466c957ed7SJacopo Mondi 	/* Use the link freq computed at ov5640_update_pixel_rate() time. */
13476c957ed7SJacopo Mondi 	link_freq = sensor->current_link_freq;
13486c957ed7SJacopo Mondi 
1349aa288248SMaxime Ripard 	/*
13506c957ed7SJacopo Mondi 	 * - mipi_div - Additional divider for the MIPI lane clock.
13516c957ed7SJacopo Mondi 	 *
13526c957ed7SJacopo Mondi 	 * Higher link frequencies would make sysclk > 1GHz.
13536c957ed7SJacopo Mondi 	 * Keep the sysclk low and do not divide in the MIPI domain.
1354aa288248SMaxime Ripard 	 */
13556c957ed7SJacopo Mondi 	if (link_freq > OV5640_LINK_RATE_MAX)
13566c957ed7SJacopo Mondi 		mipi_div = 1;
1357aa288248SMaxime Ripard 	else
13586c957ed7SJacopo Mondi 		mipi_div = 2;
1359aa288248SMaxime Ripard 
13606c957ed7SJacopo Mondi 	sysclk = link_freq * mipi_div;
13616c957ed7SJacopo Mondi 	ov5640_calc_sys_clk(sensor, sysclk, &prediv, &mult, &sysdiv);
1362aa288248SMaxime Ripard 
13636c957ed7SJacopo Mondi 	/*
13646c957ed7SJacopo Mondi 	 * Adjust PLL parameters to maintain the MIPI_SCLK-to-PCLK ratio.
13656c957ed7SJacopo Mondi 	 *
13666c957ed7SJacopo Mondi 	 * - root_div = 2 (fixed)
13676c957ed7SJacopo Mondi 	 * - bit_div : MIPI 8-bit = 2; MIPI 10-bit = 2.5
13686c957ed7SJacopo Mondi 	 * - pclk_div = 1 (fixed)
13696c957ed7SJacopo Mondi 	 * - p_div  = (2 lanes ? mipi_div : 2 * mipi_div)
13706c957ed7SJacopo Mondi 	 *
13716c957ed7SJacopo Mondi 	 * This results in the following MIPI_SCLK depending on the number
13726c957ed7SJacopo Mondi 	 * of lanes:
13736c957ed7SJacopo Mondi 	 *
13746c957ed7SJacopo Mondi 	 * - 2 lanes: MIPI_SCLK = (4 or 5) * PCLK
13756c957ed7SJacopo Mondi 	 * - 1 lanes: MIPI_SCLK = (8 or 10) * PCLK
13766c957ed7SJacopo Mondi 	 */
13776c957ed7SJacopo Mondi 	root_div = OV5640_PLL_CTRL3_PLL_ROOT_DIV_2;
13786c957ed7SJacopo Mondi 	bit_div =  OV5640_PLL_CTRL0_MIPI_MODE_8BIT;
13796c957ed7SJacopo Mondi 	pclk_div = ilog2(OV5640_PCLK_ROOT_DIV);
1380aa288248SMaxime Ripard 
13816c957ed7SJacopo Mondi 	/*
13826c957ed7SJacopo Mondi 	 * Scaler clock:
13836c957ed7SJacopo Mondi 	 * - YUV: PCLK >= 2 * SCLK
13846c957ed7SJacopo Mondi 	 * - RAW or JPEG: PCLK >= SCLK
13856c957ed7SJacopo Mondi 	 * - sclk2x_div = sclk_div / 2
13866c957ed7SJacopo Mondi 	 */
13876c957ed7SJacopo Mondi 	sclk_div = ilog2(OV5640_SCLK_ROOT_DIV);
13886c957ed7SJacopo Mondi 	sclk2x_div = ilog2(OV5640_SCLK2X_ROOT_DIV);
13896c957ed7SJacopo Mondi 
13906c957ed7SJacopo Mondi 	/*
13916c957ed7SJacopo Mondi 	 * Set the pixel clock period expressed in ns with 1-bit decimal
13926c957ed7SJacopo Mondi 	 * (0x01=0.5ns).
13936c957ed7SJacopo Mondi 	 *
13946c957ed7SJacopo Mondi 	 * The register is very briefly documented. In the OV5645 datasheet it
13956c957ed7SJacopo Mondi 	 * is described as (2 * pclk period), and from testing it seems the
13966c957ed7SJacopo Mondi 	 * actual definition is 2 * 8-bit sample period.
13976c957ed7SJacopo Mondi 	 *
13986c957ed7SJacopo Mondi 	 * 2 * sample_period = (mipi_clk * 2 * num_lanes / bpp) * (bpp / 8) / 2
13996c957ed7SJacopo Mondi 	 */
14006c957ed7SJacopo Mondi 	num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes;
14016c957ed7SJacopo Mondi 	sample_rate = (link_freq * mipi_div * num_lanes * 2) / 16;
14026c957ed7SJacopo Mondi 	pclk_period = 2000000000UL / sample_rate;
14036c957ed7SJacopo Mondi 
14046c957ed7SJacopo Mondi 	/* Program the clock tree registers. */
14056c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0, 0x0f, bit_div);
14066c957ed7SJacopo Mondi 	if (ret)
14076c957ed7SJacopo Mondi 		return ret;
14086c957ed7SJacopo Mondi 
14096c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, 0xff,
14106c957ed7SJacopo Mondi 			     (sysdiv << 4) | mipi_div);
1411aa288248SMaxime Ripard 	if (ret)
1412aa288248SMaxime Ripard 		return ret;
1413aa288248SMaxime Ripard 
1414aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2, 0xff, mult);
1415aa288248SMaxime Ripard 	if (ret)
1416aa288248SMaxime Ripard 		return ret;
1417aa288248SMaxime Ripard 
14186c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3, 0x1f,
14196c957ed7SJacopo Mondi 			     root_div | prediv);
1420aa288248SMaxime Ripard 	if (ret)
1421aa288248SMaxime Ripard 		return ret;
1422aa288248SMaxime Ripard 
14236c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
14246c957ed7SJacopo Mondi 			     (pclk_div << 4) | (sclk2x_div << 2) | sclk_div);
14256c957ed7SJacopo Mondi 	if (ret)
14266c957ed7SJacopo Mondi 		return ret;
14276c957ed7SJacopo Mondi 
14286c957ed7SJacopo Mondi 	return ov5640_write_reg(sensor, OV5640_REG_PCLK_PERIOD, pclk_period);
14296c957ed7SJacopo Mondi }
14306c957ed7SJacopo Mondi 
14316c957ed7SJacopo Mondi static u32 ov5640_calc_pixel_rate(struct ov5640_dev *sensor)
14326c957ed7SJacopo Mondi {
14333145efcdSJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
14345113d5b3SJacopo Mondi 	const struct ov5640_timings *timings = &mode->dvp_timings;
14356c957ed7SJacopo Mondi 	u32 rate;
14366c957ed7SJacopo Mondi 
14375113d5b3SJacopo Mondi 	rate = timings->htot * (timings->crop.height + timings->vblank_def);
14386c957ed7SJacopo Mondi 	rate *= ov5640_framerates[sensor->current_fr];
14396c957ed7SJacopo Mondi 
14406c957ed7SJacopo Mondi 	return rate;
1441aa288248SMaxime Ripard }
1442aa288248SMaxime Ripard 
1443aa288248SMaxime Ripard static unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor,
1444aa288248SMaxime Ripard 				      unsigned long rate,
1445aa288248SMaxime Ripard 				      u8 *pll_prediv, u8 *pll_mult, u8 *sysdiv,
1446aa288248SMaxime Ripard 				      u8 *pll_rdiv, u8 *bit_div, u8 *pclk_div)
1447aa288248SMaxime Ripard {
1448aa288248SMaxime Ripard 	unsigned long _rate = rate * OV5640_PLL_ROOT_DIV * OV5640_BIT_DIV *
1449aa288248SMaxime Ripard 				OV5640_PCLK_ROOT_DIV;
1450aa288248SMaxime Ripard 
1451aa288248SMaxime Ripard 	_rate = ov5640_calc_sys_clk(sensor, _rate, pll_prediv, pll_mult,
1452aa288248SMaxime Ripard 				    sysdiv);
1453aa288248SMaxime Ripard 	*pll_rdiv = OV5640_PLL_ROOT_DIV;
1454aa288248SMaxime Ripard 	*bit_div = OV5640_BIT_DIV;
1455aa288248SMaxime Ripard 	*pclk_div = OV5640_PCLK_ROOT_DIV;
1456aa288248SMaxime Ripard 
1457aa288248SMaxime Ripard 	return _rate / *pll_rdiv / *bit_div / *pclk_div;
1458aa288248SMaxime Ripard }
1459aa288248SMaxime Ripard 
14606c957ed7SJacopo Mondi static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor)
1461aa288248SMaxime Ripard {
1462aa288248SMaxime Ripard 	u8 prediv, mult, sysdiv, pll_rdiv, bit_div, pclk_div;
14636c957ed7SJacopo Mondi 	u32 rate;
1464aa288248SMaxime Ripard 	int ret;
1465aa288248SMaxime Ripard 
14666c957ed7SJacopo Mondi 	rate = ov5640_calc_pixel_rate(sensor);
14676c957ed7SJacopo Mondi 	rate *= ov5640_code_to_bpp(sensor->fmt.code);
14686c957ed7SJacopo Mondi 	rate /= sensor->ep.bus.parallel.bus_width;
14696c957ed7SJacopo Mondi 
1470aa288248SMaxime Ripard 	ov5640_calc_pclk(sensor, rate, &prediv, &mult, &sysdiv, &pll_rdiv,
1471aa288248SMaxime Ripard 			 &bit_div, &pclk_div);
1472aa288248SMaxime Ripard 
1473aa288248SMaxime Ripard 	if (bit_div == 2)
1474aa288248SMaxime Ripard 		bit_div = 8;
1475aa288248SMaxime Ripard 
1476aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0,
1477aa288248SMaxime Ripard 			     0x0f, bit_div);
1478aa288248SMaxime Ripard 	if (ret)
1479aa288248SMaxime Ripard 		return ret;
1480aa288248SMaxime Ripard 
1481aa288248SMaxime Ripard 	/*
1482aa288248SMaxime Ripard 	 * We need to set sysdiv according to the clock, and to clear
1483aa288248SMaxime Ripard 	 * the MIPI divider.
1484aa288248SMaxime Ripard 	 */
1485aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1,
1486aa288248SMaxime Ripard 			     0xff, sysdiv << 4);
1487aa288248SMaxime Ripard 	if (ret)
1488aa288248SMaxime Ripard 		return ret;
1489aa288248SMaxime Ripard 
1490aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2,
1491aa288248SMaxime Ripard 			     0xff, mult);
1492aa288248SMaxime Ripard 	if (ret)
1493aa288248SMaxime Ripard 		return ret;
1494aa288248SMaxime Ripard 
1495aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3,
1496aa288248SMaxime Ripard 			     0x1f, prediv | ((pll_rdiv - 1) << 4));
1497aa288248SMaxime Ripard 	if (ret)
1498aa288248SMaxime Ripard 		return ret;
1499aa288248SMaxime Ripard 
1500aa288248SMaxime Ripard 	return ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x30,
1501aa288248SMaxime Ripard 			      (ilog2(pclk_div) << 4));
1502aa288248SMaxime Ripard }
1503aa288248SMaxime Ripard 
15047cb013b1SChen-Yu Tsai /* set JPEG framing sizes */
15057cb013b1SChen-Yu Tsai static int ov5640_set_jpeg_timings(struct ov5640_dev *sensor,
15067cb013b1SChen-Yu Tsai 				   const struct ov5640_mode_info *mode)
15077cb013b1SChen-Yu Tsai {
15087cb013b1SChen-Yu Tsai 	int ret;
15097cb013b1SChen-Yu Tsai 
15102b5c18f9SChen-Yu Tsai 	/*
15112b5c18f9SChen-Yu Tsai 	 * compression mode 3 timing
15122b5c18f9SChen-Yu Tsai 	 *
15132b5c18f9SChen-Yu Tsai 	 * Data is transmitted with programmable width (VFIFO_HSIZE).
15142b5c18f9SChen-Yu Tsai 	 * No padding done. Last line may have less data. Varying
15152b5c18f9SChen-Yu Tsai 	 * number of lines per frame, depending on amount of data.
15162b5c18f9SChen-Yu Tsai 	 */
15172b5c18f9SChen-Yu Tsai 	ret = ov5640_mod_reg(sensor, OV5640_REG_JPG_MODE_SELECT, 0x7, 0x3);
15182b5c18f9SChen-Yu Tsai 	if (ret < 0)
15192b5c18f9SChen-Yu Tsai 		return ret;
15202b5c18f9SChen-Yu Tsai 
15215113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_VFIFO_HSIZE, mode->width);
15227cb013b1SChen-Yu Tsai 	if (ret < 0)
15237cb013b1SChen-Yu Tsai 		return ret;
15247cb013b1SChen-Yu Tsai 
15255113d5b3SJacopo Mondi 	return ov5640_write_reg16(sensor, OV5640_REG_VFIFO_VSIZE, mode->height);
15267cb013b1SChen-Yu Tsai }
15277cb013b1SChen-Yu Tsai 
152819a81c14SSteve Longerbeam /* download ov5640 settings to sensor through i2c */
1529bad1774eSJacopo Mondi static int ov5640_set_timings(struct ov5640_dev *sensor,
1530bad1774eSJacopo Mondi 			      const struct ov5640_mode_info *mode)
1531bad1774eSJacopo Mondi {
15325113d5b3SJacopo Mondi 	const struct ov5640_timings *timings;
15335113d5b3SJacopo Mondi 	const struct v4l2_rect *analog_crop;
15345113d5b3SJacopo Mondi 	const struct v4l2_rect *crop;
1535bad1774eSJacopo Mondi 	int ret;
1536bad1774eSJacopo Mondi 
15377cb013b1SChen-Yu Tsai 	if (sensor->fmt.code == MEDIA_BUS_FMT_JPEG_1X8) {
15387cb013b1SChen-Yu Tsai 		ret = ov5640_set_jpeg_timings(sensor, mode);
15397cb013b1SChen-Yu Tsai 		if (ret < 0)
15407cb013b1SChen-Yu Tsai 			return ret;
15417cb013b1SChen-Yu Tsai 	}
15427cb013b1SChen-Yu Tsai 
15432de6bb97SJacopo Mondi 	timings = ov5640_timings(sensor, mode);
15445113d5b3SJacopo Mondi 	analog_crop = &timings->analog_crop;
15455113d5b3SJacopo Mondi 	crop = &timings->crop;
15465113d5b3SJacopo Mondi 
15473145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HS,
15483145efcdSJacopo Mondi 				 analog_crop->left);
1549bad1774eSJacopo Mondi 	if (ret < 0)
1550bad1774eSJacopo Mondi 		return ret;
1551bad1774eSJacopo Mondi 
15523145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VS,
15533145efcdSJacopo Mondi 				 analog_crop->top);
15543145efcdSJacopo Mondi 	if (ret < 0)
15553145efcdSJacopo Mondi 		return ret;
15563145efcdSJacopo Mondi 
15573145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HW,
15583145efcdSJacopo Mondi 				 analog_crop->left + analog_crop->width - 1);
15593145efcdSJacopo Mondi 	if (ret < 0)
15603145efcdSJacopo Mondi 		return ret;
15613145efcdSJacopo Mondi 
15623145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VH,
15633145efcdSJacopo Mondi 				 analog_crop->top + analog_crop->height - 1);
15643145efcdSJacopo Mondi 	if (ret < 0)
15653145efcdSJacopo Mondi 		return ret;
15663145efcdSJacopo Mondi 
15673145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HOFFS, crop->left);
15683145efcdSJacopo Mondi 	if (ret < 0)
15693145efcdSJacopo Mondi 		return ret;
15703145efcdSJacopo Mondi 
15713145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VOFFS, crop->top);
15723145efcdSJacopo Mondi 	if (ret < 0)
15733145efcdSJacopo Mondi 		return ret;
15743145efcdSJacopo Mondi 
15755113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->width);
15763145efcdSJacopo Mondi 	if (ret < 0)
15773145efcdSJacopo Mondi 		return ret;
15783145efcdSJacopo Mondi 
15795113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, mode->height);
1580bad1774eSJacopo Mondi 	if (ret < 0)
1581bad1774eSJacopo Mondi 		return ret;
1582bad1774eSJacopo Mondi 
15835113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, timings->htot);
1584bad1774eSJacopo Mondi 	if (ret < 0)
1585bad1774eSJacopo Mondi 		return ret;
1586bad1774eSJacopo Mondi 
15873145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS,
15885113d5b3SJacopo Mondi 				 mode->height + timings->vblank_def);
15893145efcdSJacopo Mondi 	if (ret < 0)
15903145efcdSJacopo Mondi 		return ret;
15913145efcdSJacopo Mondi 
15923145efcdSJacopo Mondi 	return 0;
1593bad1774eSJacopo Mondi }
1594bad1774eSJacopo Mondi 
1595e4359019SJacopo Mondi static void ov5640_load_regs(struct ov5640_dev *sensor,
1596e4359019SJacopo Mondi 			     const struct reg_value *regs, unsigned int regnum)
159719a81c14SSteve Longerbeam {
159819a81c14SSteve Longerbeam 	unsigned int i;
159919a81c14SSteve Longerbeam 	u32 delay_ms;
160019a81c14SSteve Longerbeam 	u16 reg_addr;
160119a81c14SSteve Longerbeam 	u8 mask, val;
160219a81c14SSteve Longerbeam 	int ret = 0;
160319a81c14SSteve Longerbeam 
1604e4359019SJacopo Mondi 	for (i = 0; i < regnum; ++i, ++regs) {
160519a81c14SSteve Longerbeam 		delay_ms = regs->delay_ms;
160619a81c14SSteve Longerbeam 		reg_addr = regs->reg_addr;
160719a81c14SSteve Longerbeam 		val = regs->val;
160819a81c14SSteve Longerbeam 		mask = regs->mask;
160919a81c14SSteve Longerbeam 
16103b987d70SLad Prabhakar 		/* remain in power down mode for DVP */
16113b987d70SLad Prabhakar 		if (regs->reg_addr == OV5640_REG_SYS_CTRL0 &&
16123b987d70SLad Prabhakar 		    val == OV5640_REG_SYS_CTRL0_SW_PWUP &&
16138e823f5cSJacopo Mondi 		    !ov5640_is_csi2(sensor))
16143b987d70SLad Prabhakar 			continue;
16153b987d70SLad Prabhakar 
161619a81c14SSteve Longerbeam 		if (mask)
161719a81c14SSteve Longerbeam 			ret = ov5640_mod_reg(sensor, reg_addr, mask, val);
161819a81c14SSteve Longerbeam 		else
161919a81c14SSteve Longerbeam 			ret = ov5640_write_reg(sensor, reg_addr, val);
162019a81c14SSteve Longerbeam 		if (ret)
162119a81c14SSteve Longerbeam 			break;
162219a81c14SSteve Longerbeam 
162319a81c14SSteve Longerbeam 		if (delay_ms)
162419a81c14SSteve Longerbeam 			usleep_range(1000 * delay_ms, 1000 * delay_ms + 100);
162519a81c14SSteve Longerbeam 	}
162619a81c14SSteve Longerbeam }
162719a81c14SSteve Longerbeam 
1628dc29a1c1SHugues Fruchet static int ov5640_set_autoexposure(struct ov5640_dev *sensor, bool on)
1629dc29a1c1SHugues Fruchet {
1630dc29a1c1SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
1631dc29a1c1SHugues Fruchet 			      BIT(0), on ? 0 : BIT(0));
1632dc29a1c1SHugues Fruchet }
1633dc29a1c1SHugues Fruchet 
163419a81c14SSteve Longerbeam /* read exposure, in number of line periods */
163519a81c14SSteve Longerbeam static int ov5640_get_exposure(struct ov5640_dev *sensor)
163619a81c14SSteve Longerbeam {
163719a81c14SSteve Longerbeam 	int exp, ret;
163819a81c14SSteve Longerbeam 	u8 temp;
163919a81c14SSteve Longerbeam 
164019a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_HI, &temp);
164119a81c14SSteve Longerbeam 	if (ret)
164219a81c14SSteve Longerbeam 		return ret;
164319a81c14SSteve Longerbeam 	exp = ((int)temp & 0x0f) << 16;
164419a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_MED, &temp);
164519a81c14SSteve Longerbeam 	if (ret)
164619a81c14SSteve Longerbeam 		return ret;
164719a81c14SSteve Longerbeam 	exp |= ((int)temp << 8);
164819a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_LO, &temp);
164919a81c14SSteve Longerbeam 	if (ret)
165019a81c14SSteve Longerbeam 		return ret;
165119a81c14SSteve Longerbeam 	exp |= (int)temp;
165219a81c14SSteve Longerbeam 
165319a81c14SSteve Longerbeam 	return exp >> 4;
165419a81c14SSteve Longerbeam }
165519a81c14SSteve Longerbeam 
165619a81c14SSteve Longerbeam /* write exposure, given number of line periods */
165719a81c14SSteve Longerbeam static int ov5640_set_exposure(struct ov5640_dev *sensor, u32 exposure)
165819a81c14SSteve Longerbeam {
165919a81c14SSteve Longerbeam 	int ret;
166019a81c14SSteve Longerbeam 
166119a81c14SSteve Longerbeam 	exposure <<= 4;
166219a81c14SSteve Longerbeam 
166319a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor,
166419a81c14SSteve Longerbeam 			       OV5640_REG_AEC_PK_EXPOSURE_LO,
166519a81c14SSteve Longerbeam 			       exposure & 0xff);
166619a81c14SSteve Longerbeam 	if (ret)
166719a81c14SSteve Longerbeam 		return ret;
166819a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor,
166919a81c14SSteve Longerbeam 			       OV5640_REG_AEC_PK_EXPOSURE_MED,
167019a81c14SSteve Longerbeam 			       (exposure >> 8) & 0xff);
167119a81c14SSteve Longerbeam 	if (ret)
167219a81c14SSteve Longerbeam 		return ret;
167319a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor,
167419a81c14SSteve Longerbeam 				OV5640_REG_AEC_PK_EXPOSURE_HI,
167519a81c14SSteve Longerbeam 				(exposure >> 16) & 0x0f);
167619a81c14SSteve Longerbeam }
167719a81c14SSteve Longerbeam 
167819a81c14SSteve Longerbeam static int ov5640_get_gain(struct ov5640_dev *sensor)
167919a81c14SSteve Longerbeam {
168019a81c14SSteve Longerbeam 	u16 gain;
168119a81c14SSteve Longerbeam 	int ret;
168219a81c14SSteve Longerbeam 
168319a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN, &gain);
168419a81c14SSteve Longerbeam 	if (ret)
168519a81c14SSteve Longerbeam 		return ret;
168619a81c14SSteve Longerbeam 
168719a81c14SSteve Longerbeam 	return gain & 0x3ff;
168819a81c14SSteve Longerbeam }
168919a81c14SSteve Longerbeam 
16903cca8ef5SHugues Fruchet static int ov5640_set_gain(struct ov5640_dev *sensor, int gain)
16913cca8ef5SHugues Fruchet {
16923cca8ef5SHugues Fruchet 	return ov5640_write_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN,
16933cca8ef5SHugues Fruchet 				  (u16)gain & 0x3ff);
16943cca8ef5SHugues Fruchet }
16953cca8ef5SHugues Fruchet 
16963cca8ef5SHugues Fruchet static int ov5640_set_autogain(struct ov5640_dev *sensor, bool on)
16973cca8ef5SHugues Fruchet {
16983cca8ef5SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
16993cca8ef5SHugues Fruchet 			      BIT(1), on ? 0 : BIT(1));
17003cca8ef5SHugues Fruchet }
17013cca8ef5SHugues Fruchet 
1702f22996dbSHugues Fruchet static int ov5640_set_stream_dvp(struct ov5640_dev *sensor, bool on)
1703f22996dbSHugues Fruchet {
17043b987d70SLad Prabhakar 	return ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0, on ?
17053b987d70SLad Prabhakar 				OV5640_REG_SYS_CTRL0_SW_PWUP :
17063b987d70SLad Prabhakar 				OV5640_REG_SYS_CTRL0_SW_PWDN);
1707f22996dbSHugues Fruchet }
1708f22996dbSHugues Fruchet 
1709f22996dbSHugues Fruchet static int ov5640_set_stream_mipi(struct ov5640_dev *sensor, bool on)
171019a81c14SSteve Longerbeam {
171119a81c14SSteve Longerbeam 	int ret;
171219a81c14SSteve Longerbeam 
1713aa4bb8b8SJacopo Mondi 	/*
1714aa4bb8b8SJacopo Mondi 	 * Enable/disable the MIPI interface
1715aa4bb8b8SJacopo Mondi 	 *
1716aa4bb8b8SJacopo Mondi 	 * 0x300e = on ? 0x45 : 0x40
1717aa4bb8b8SJacopo Mondi 	 *
1718aa4bb8b8SJacopo Mondi 	 * FIXME: the sensor manual (version 2.03) reports
1719aa4bb8b8SJacopo Mondi 	 * [7:5] = 000  : 1 data lane mode
1720aa4bb8b8SJacopo Mondi 	 * [7:5] = 001  : 2 data lanes mode
1721aa4bb8b8SJacopo Mondi 	 * But this settings do not work, while the following ones
1722aa4bb8b8SJacopo Mondi 	 * have been validated for 2 data lanes mode.
1723aa4bb8b8SJacopo Mondi 	 *
1724aa4bb8b8SJacopo Mondi 	 * [7:5] = 010	: 2 data lanes mode
1725aa4bb8b8SJacopo Mondi 	 * [4] = 0	: Power up MIPI HS Tx
1726aa4bb8b8SJacopo Mondi 	 * [3] = 0	: Power up MIPI LS Rx
1727aa4bb8b8SJacopo Mondi 	 * [2] = 1/0	: MIPI interface enable/disable
1728aa4bb8b8SJacopo Mondi 	 * [1:0] = 01/00: FIXME: 'debug'
1729aa4bb8b8SJacopo Mondi 	 */
1730aa4bb8b8SJacopo Mondi 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00,
1731aa4bb8b8SJacopo Mondi 			       on ? 0x45 : 0x40);
173219a81c14SSteve Longerbeam 	if (ret)
173319a81c14SSteve Longerbeam 		return ret;
173419a81c14SSteve Longerbeam 
173519a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_FRAME_CTRL01,
173619a81c14SSteve Longerbeam 				on ? 0x00 : 0x0f);
173719a81c14SSteve Longerbeam }
173819a81c14SSteve Longerbeam 
173919a81c14SSteve Longerbeam static int ov5640_get_sysclk(struct ov5640_dev *sensor)
174019a81c14SSteve Longerbeam {
174119a81c14SSteve Longerbeam 	 /* calculate sysclk */
174219a81c14SSteve Longerbeam 	u32 xvclk = sensor->xclk_freq / 10000;
174319a81c14SSteve Longerbeam 	u32 multiplier, prediv, VCO, sysdiv, pll_rdiv;
174419a81c14SSteve Longerbeam 	u32 sclk_rdiv_map[] = {1, 2, 4, 8};
174519a81c14SSteve Longerbeam 	u32 bit_div2x = 1, sclk_rdiv, sysclk;
174619a81c14SSteve Longerbeam 	u8 temp1, temp2;
174719a81c14SSteve Longerbeam 	int ret;
174819a81c14SSteve Longerbeam 
174919a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL0, &temp1);
175019a81c14SSteve Longerbeam 	if (ret)
175119a81c14SSteve Longerbeam 		return ret;
175219a81c14SSteve Longerbeam 	temp2 = temp1 & 0x0f;
175319a81c14SSteve Longerbeam 	if (temp2 == 8 || temp2 == 10)
175419a81c14SSteve Longerbeam 		bit_div2x = temp2 / 2;
175519a81c14SSteve Longerbeam 
175619a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL1, &temp1);
175719a81c14SSteve Longerbeam 	if (ret)
175819a81c14SSteve Longerbeam 		return ret;
175919a81c14SSteve Longerbeam 	sysdiv = temp1 >> 4;
176019a81c14SSteve Longerbeam 	if (sysdiv == 0)
176119a81c14SSteve Longerbeam 		sysdiv = 16;
176219a81c14SSteve Longerbeam 
176319a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL2, &temp1);
176419a81c14SSteve Longerbeam 	if (ret)
176519a81c14SSteve Longerbeam 		return ret;
176619a81c14SSteve Longerbeam 	multiplier = temp1;
176719a81c14SSteve Longerbeam 
176819a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL3, &temp1);
176919a81c14SSteve Longerbeam 	if (ret)
177019a81c14SSteve Longerbeam 		return ret;
177119a81c14SSteve Longerbeam 	prediv = temp1 & 0x0f;
177219a81c14SSteve Longerbeam 	pll_rdiv = ((temp1 >> 4) & 0x01) + 1;
177319a81c14SSteve Longerbeam 
177419a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, &temp1);
177519a81c14SSteve Longerbeam 	if (ret)
177619a81c14SSteve Longerbeam 		return ret;
177719a81c14SSteve Longerbeam 	temp2 = temp1 & 0x03;
177819a81c14SSteve Longerbeam 	sclk_rdiv = sclk_rdiv_map[temp2];
177919a81c14SSteve Longerbeam 
178019a81c14SSteve Longerbeam 	if (!prediv || !sysdiv || !pll_rdiv || !bit_div2x)
178119a81c14SSteve Longerbeam 		return -EINVAL;
178219a81c14SSteve Longerbeam 
178319a81c14SSteve Longerbeam 	VCO = xvclk * multiplier / prediv;
178419a81c14SSteve Longerbeam 
178519a81c14SSteve Longerbeam 	sysclk = VCO / sysdiv / pll_rdiv * 2 / bit_div2x / sclk_rdiv;
178619a81c14SSteve Longerbeam 
178719a81c14SSteve Longerbeam 	return sysclk;
178819a81c14SSteve Longerbeam }
178919a81c14SSteve Longerbeam 
179019a81c14SSteve Longerbeam static int ov5640_set_night_mode(struct ov5640_dev *sensor)
179119a81c14SSteve Longerbeam {
179219a81c14SSteve Longerbeam 	 /* read HTS from register settings */
179319a81c14SSteve Longerbeam 	u8 mode;
179419a81c14SSteve Longerbeam 	int ret;
179519a81c14SSteve Longerbeam 
179619a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_CTRL00, &mode);
179719a81c14SSteve Longerbeam 	if (ret)
179819a81c14SSteve Longerbeam 		return ret;
179919a81c14SSteve Longerbeam 	mode &= 0xfb;
180019a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL00, mode);
180119a81c14SSteve Longerbeam }
180219a81c14SSteve Longerbeam 
180319a81c14SSteve Longerbeam static int ov5640_get_hts(struct ov5640_dev *sensor)
180419a81c14SSteve Longerbeam {
180519a81c14SSteve Longerbeam 	/* read HTS from register settings */
180619a81c14SSteve Longerbeam 	u16 hts;
180719a81c14SSteve Longerbeam 	int ret;
180819a81c14SSteve Longerbeam 
180919a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_HTS, &hts);
181019a81c14SSteve Longerbeam 	if (ret)
181119a81c14SSteve Longerbeam 		return ret;
181219a81c14SSteve Longerbeam 	return hts;
181319a81c14SSteve Longerbeam }
181419a81c14SSteve Longerbeam 
181519a81c14SSteve Longerbeam static int ov5640_get_vts(struct ov5640_dev *sensor)
181619a81c14SSteve Longerbeam {
181719a81c14SSteve Longerbeam 	u16 vts;
181819a81c14SSteve Longerbeam 	int ret;
181919a81c14SSteve Longerbeam 
182019a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_VTS, &vts);
182119a81c14SSteve Longerbeam 	if (ret)
182219a81c14SSteve Longerbeam 		return ret;
182319a81c14SSteve Longerbeam 	return vts;
182419a81c14SSteve Longerbeam }
182519a81c14SSteve Longerbeam 
182619a81c14SSteve Longerbeam static int ov5640_set_vts(struct ov5640_dev *sensor, int vts)
182719a81c14SSteve Longerbeam {
182819a81c14SSteve Longerbeam 	return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, vts);
182919a81c14SSteve Longerbeam }
183019a81c14SSteve Longerbeam 
183119a81c14SSteve Longerbeam static int ov5640_get_light_freq(struct ov5640_dev *sensor)
183219a81c14SSteve Longerbeam {
183319a81c14SSteve Longerbeam 	/* get banding filter value */
183419a81c14SSteve Longerbeam 	int ret, light_freq = 0;
183519a81c14SSteve Longerbeam 	u8 temp, temp1;
183619a81c14SSteve Longerbeam 
183719a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL01, &temp);
183819a81c14SSteve Longerbeam 	if (ret)
183919a81c14SSteve Longerbeam 		return ret;
184019a81c14SSteve Longerbeam 
184119a81c14SSteve Longerbeam 	if (temp & 0x80) {
184219a81c14SSteve Longerbeam 		/* manual */
184319a81c14SSteve Longerbeam 		ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL00,
184419a81c14SSteve Longerbeam 				      &temp1);
184519a81c14SSteve Longerbeam 		if (ret)
184619a81c14SSteve Longerbeam 			return ret;
184719a81c14SSteve Longerbeam 		if (temp1 & 0x04) {
184819a81c14SSteve Longerbeam 			/* 50Hz */
184919a81c14SSteve Longerbeam 			light_freq = 50;
185019a81c14SSteve Longerbeam 		} else {
185119a81c14SSteve Longerbeam 			/* 60Hz */
185219a81c14SSteve Longerbeam 			light_freq = 60;
185319a81c14SSteve Longerbeam 		}
185419a81c14SSteve Longerbeam 	} else {
185519a81c14SSteve Longerbeam 		/* auto */
185619a81c14SSteve Longerbeam 		ret = ov5640_read_reg(sensor, OV5640_REG_SIGMADELTA_CTRL0C,
185719a81c14SSteve Longerbeam 				      &temp1);
185819a81c14SSteve Longerbeam 		if (ret)
185919a81c14SSteve Longerbeam 			return ret;
186019a81c14SSteve Longerbeam 
186119a81c14SSteve Longerbeam 		if (temp1 & 0x01) {
186219a81c14SSteve Longerbeam 			/* 50Hz */
186319a81c14SSteve Longerbeam 			light_freq = 50;
186419a81c14SSteve Longerbeam 		} else {
186519a81c14SSteve Longerbeam 			/* 60Hz */
186619a81c14SSteve Longerbeam 		}
186719a81c14SSteve Longerbeam 	}
186819a81c14SSteve Longerbeam 
186919a81c14SSteve Longerbeam 	return light_freq;
187019a81c14SSteve Longerbeam }
187119a81c14SSteve Longerbeam 
187219a81c14SSteve Longerbeam static int ov5640_set_bandingfilter(struct ov5640_dev *sensor)
187319a81c14SSteve Longerbeam {
187419a81c14SSteve Longerbeam 	u32 band_step60, max_band60, band_step50, max_band50, prev_vts;
187519a81c14SSteve Longerbeam 	int ret;
187619a81c14SSteve Longerbeam 
187719a81c14SSteve Longerbeam 	/* read preview PCLK */
187819a81c14SSteve Longerbeam 	ret = ov5640_get_sysclk(sensor);
187919a81c14SSteve Longerbeam 	if (ret < 0)
188019a81c14SSteve Longerbeam 		return ret;
188119a81c14SSteve Longerbeam 	if (ret == 0)
188219a81c14SSteve Longerbeam 		return -EINVAL;
188319a81c14SSteve Longerbeam 	sensor->prev_sysclk = ret;
188419a81c14SSteve Longerbeam 	/* read preview HTS */
188519a81c14SSteve Longerbeam 	ret = ov5640_get_hts(sensor);
188619a81c14SSteve Longerbeam 	if (ret < 0)
188719a81c14SSteve Longerbeam 		return ret;
188819a81c14SSteve Longerbeam 	if (ret == 0)
188919a81c14SSteve Longerbeam 		return -EINVAL;
189019a81c14SSteve Longerbeam 	sensor->prev_hts = ret;
189119a81c14SSteve Longerbeam 
189219a81c14SSteve Longerbeam 	/* read preview VTS */
189319a81c14SSteve Longerbeam 	ret = ov5640_get_vts(sensor);
189419a81c14SSteve Longerbeam 	if (ret < 0)
189519a81c14SSteve Longerbeam 		return ret;
189619a81c14SSteve Longerbeam 	prev_vts = ret;
189719a81c14SSteve Longerbeam 
189819a81c14SSteve Longerbeam 	/* calculate banding filter */
189919a81c14SSteve Longerbeam 	/* 60Hz */
190019a81c14SSteve Longerbeam 	band_step60 = sensor->prev_sysclk * 100 / sensor->prev_hts * 100 / 120;
190119a81c14SSteve Longerbeam 	ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B60_STEP, band_step60);
190219a81c14SSteve Longerbeam 	if (ret)
190319a81c14SSteve Longerbeam 		return ret;
190419a81c14SSteve Longerbeam 	if (!band_step60)
190519a81c14SSteve Longerbeam 		return -EINVAL;
190619a81c14SSteve Longerbeam 	max_band60 = (int)((prev_vts - 4) / band_step60);
190719a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0D, max_band60);
190819a81c14SSteve Longerbeam 	if (ret)
190919a81c14SSteve Longerbeam 		return ret;
191019a81c14SSteve Longerbeam 
191119a81c14SSteve Longerbeam 	/* 50Hz */
191219a81c14SSteve Longerbeam 	band_step50 = sensor->prev_sysclk * 100 / sensor->prev_hts;
191319a81c14SSteve Longerbeam 	ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B50_STEP, band_step50);
191419a81c14SSteve Longerbeam 	if (ret)
191519a81c14SSteve Longerbeam 		return ret;
191619a81c14SSteve Longerbeam 	if (!band_step50)
191719a81c14SSteve Longerbeam 		return -EINVAL;
191819a81c14SSteve Longerbeam 	max_band50 = (int)((prev_vts - 4) / band_step50);
191919a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0E, max_band50);
192019a81c14SSteve Longerbeam }
192119a81c14SSteve Longerbeam 
192219a81c14SSteve Longerbeam static int ov5640_set_ae_target(struct ov5640_dev *sensor, int target)
192319a81c14SSteve Longerbeam {
192419a81c14SSteve Longerbeam 	/* stable in high */
192519a81c14SSteve Longerbeam 	u32 fast_high, fast_low;
192619a81c14SSteve Longerbeam 	int ret;
192719a81c14SSteve Longerbeam 
192819a81c14SSteve Longerbeam 	sensor->ae_low = target * 23 / 25;	/* 0.92 */
192919a81c14SSteve Longerbeam 	sensor->ae_high = target * 27 / 25;	/* 1.08 */
193019a81c14SSteve Longerbeam 
193119a81c14SSteve Longerbeam 	fast_high = sensor->ae_high << 1;
193219a81c14SSteve Longerbeam 	if (fast_high > 255)
193319a81c14SSteve Longerbeam 		fast_high = 255;
193419a81c14SSteve Longerbeam 
193519a81c14SSteve Longerbeam 	fast_low = sensor->ae_low >> 1;
193619a81c14SSteve Longerbeam 
193719a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0F, sensor->ae_high);
193819a81c14SSteve Longerbeam 	if (ret)
193919a81c14SSteve Longerbeam 		return ret;
194019a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL10, sensor->ae_low);
194119a81c14SSteve Longerbeam 	if (ret)
194219a81c14SSteve Longerbeam 		return ret;
194319a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1B, sensor->ae_high);
194419a81c14SSteve Longerbeam 	if (ret)
194519a81c14SSteve Longerbeam 		return ret;
194619a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1E, sensor->ae_low);
194719a81c14SSteve Longerbeam 	if (ret)
194819a81c14SSteve Longerbeam 		return ret;
194919a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL11, fast_high);
195019a81c14SSteve Longerbeam 	if (ret)
195119a81c14SSteve Longerbeam 		return ret;
195219a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1F, fast_low);
195319a81c14SSteve Longerbeam }
195419a81c14SSteve Longerbeam 
1955c2c3f42dSHugues Fruchet static int ov5640_get_binning(struct ov5640_dev *sensor)
195619a81c14SSteve Longerbeam {
195719a81c14SSteve Longerbeam 	u8 temp;
195819a81c14SSteve Longerbeam 	int ret;
195919a81c14SSteve Longerbeam 
196019a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_TIMING_TC_REG21, &temp);
196119a81c14SSteve Longerbeam 	if (ret)
196219a81c14SSteve Longerbeam 		return ret;
1963c2c3f42dSHugues Fruchet 
1964c2c3f42dSHugues Fruchet 	return temp & BIT(0);
196519a81c14SSteve Longerbeam }
196619a81c14SSteve Longerbeam 
1967ce85705aSHugues Fruchet static int ov5640_set_binning(struct ov5640_dev *sensor, bool enable)
1968ce85705aSHugues Fruchet {
1969ce85705aSHugues Fruchet 	int ret;
1970ce85705aSHugues Fruchet 
1971ce85705aSHugues Fruchet 	/*
1972ce85705aSHugues Fruchet 	 * TIMING TC REG21:
1973ce85705aSHugues Fruchet 	 * - [0]:	Horizontal binning enable
1974ce85705aSHugues Fruchet 	 */
1975ce85705aSHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
1976ce85705aSHugues Fruchet 			     BIT(0), enable ? BIT(0) : 0);
1977ce85705aSHugues Fruchet 	if (ret)
1978ce85705aSHugues Fruchet 		return ret;
1979ce85705aSHugues Fruchet 	/*
1980ce85705aSHugues Fruchet 	 * TIMING TC REG20:
1981ce85705aSHugues Fruchet 	 * - [0]:	Undocumented, but hardcoded init sequences
1982ce85705aSHugues Fruchet 	 *		are always setting REG21/REG20 bit 0 to same value...
1983ce85705aSHugues Fruchet 	 */
1984ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20,
1985ce85705aSHugues Fruchet 			      BIT(0), enable ? BIT(0) : 0);
1986ce85705aSHugues Fruchet }
1987ce85705aSHugues Fruchet 
198819a81c14SSteve Longerbeam static int ov5640_set_virtual_channel(struct ov5640_dev *sensor)
198919a81c14SSteve Longerbeam {
19908670d70aSHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
199119a81c14SSteve Longerbeam 	u8 temp, channel = virtual_channel;
199219a81c14SSteve Longerbeam 	int ret;
199319a81c14SSteve Longerbeam 
19948670d70aSHugues Fruchet 	if (channel > 3) {
19958670d70aSHugues Fruchet 		dev_err(&client->dev,
19968670d70aSHugues Fruchet 			"%s: wrong virtual_channel parameter, expected (0..3), got %d\n",
19978670d70aSHugues Fruchet 			__func__, channel);
199819a81c14SSteve Longerbeam 		return -EINVAL;
19998670d70aSHugues Fruchet 	}
200019a81c14SSteve Longerbeam 
200119a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_DEBUG_MODE, &temp);
200219a81c14SSteve Longerbeam 	if (ret)
200319a81c14SSteve Longerbeam 		return ret;
200419a81c14SSteve Longerbeam 	temp &= ~(3 << 6);
200519a81c14SSteve Longerbeam 	temp |= (channel << 6);
200619a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_DEBUG_MODE, temp);
200719a81c14SSteve Longerbeam }
200819a81c14SSteve Longerbeam 
200919a81c14SSteve Longerbeam static const struct ov5640_mode_info *
2010b6ae5022SJacopo Mondi ov5640_find_mode(struct ov5640_dev *sensor, int width, int height, bool nearest)
201119a81c14SSteve Longerbeam {
20123c4a7372SHugues Fruchet 	const struct ov5640_mode_info *mode;
201319a81c14SSteve Longerbeam 
2014086c25f8SMaxime Ripard 	mode = v4l2_find_nearest_size(ov5640_mode_data,
2015086c25f8SMaxime Ripard 				      ARRAY_SIZE(ov5640_mode_data),
20165113d5b3SJacopo Mondi 				      width, height, width, height);
201719a81c14SSteve Longerbeam 
20183c4a7372SHugues Fruchet 	if (!mode ||
20193145efcdSJacopo Mondi 	    (!nearest &&
20205113d5b3SJacopo Mondi 	     (mode->width != width || mode->height != height)))
20213c4a7372SHugues Fruchet 		return NULL;
202219a81c14SSteve Longerbeam 
202319a81c14SSteve Longerbeam 	return mode;
202419a81c14SSteve Longerbeam }
202519a81c14SSteve Longerbeam 
202619a81c14SSteve Longerbeam /*
202719a81c14SSteve Longerbeam  * sensor changes between scaling and subsampling, go through
202819a81c14SSteve Longerbeam  * exposure calculation
202919a81c14SSteve Longerbeam  */
203041d8d7f5SHugues Fruchet static int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor,
203141d8d7f5SHugues Fruchet 					 const struct ov5640_mode_info *mode)
203219a81c14SSteve Longerbeam {
203319a81c14SSteve Longerbeam 	u32 prev_shutter, prev_gain16;
203419a81c14SSteve Longerbeam 	u32 cap_shutter, cap_gain16;
203519a81c14SSteve Longerbeam 	u32 cap_sysclk, cap_hts, cap_vts;
203619a81c14SSteve Longerbeam 	u32 light_freq, cap_bandfilt, cap_maxband;
203719a81c14SSteve Longerbeam 	u32 cap_gain16_shutter;
203819a81c14SSteve Longerbeam 	u8 average;
203919a81c14SSteve Longerbeam 	int ret;
204019a81c14SSteve Longerbeam 
204141d8d7f5SHugues Fruchet 	if (!mode->reg_data)
204219a81c14SSteve Longerbeam 		return -EINVAL;
204319a81c14SSteve Longerbeam 
204419a81c14SSteve Longerbeam 	/* read preview shutter */
204519a81c14SSteve Longerbeam 	ret = ov5640_get_exposure(sensor);
204619a81c14SSteve Longerbeam 	if (ret < 0)
204719a81c14SSteve Longerbeam 		return ret;
204819a81c14SSteve Longerbeam 	prev_shutter = ret;
2049c2c3f42dSHugues Fruchet 	ret = ov5640_get_binning(sensor);
205019a81c14SSteve Longerbeam 	if (ret < 0)
205119a81c14SSteve Longerbeam 		return ret;
205219a81c14SSteve Longerbeam 	if (ret && mode->id != OV5640_MODE_720P_1280_720 &&
205319a81c14SSteve Longerbeam 	    mode->id != OV5640_MODE_1080P_1920_1080)
205419a81c14SSteve Longerbeam 		prev_shutter *= 2;
205519a81c14SSteve Longerbeam 
205619a81c14SSteve Longerbeam 	/* read preview gain */
205719a81c14SSteve Longerbeam 	ret = ov5640_get_gain(sensor);
205819a81c14SSteve Longerbeam 	if (ret < 0)
205919a81c14SSteve Longerbeam 		return ret;
206019a81c14SSteve Longerbeam 	prev_gain16 = ret;
206119a81c14SSteve Longerbeam 
206219a81c14SSteve Longerbeam 	/* get average */
206319a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AVG_READOUT, &average);
206419a81c14SSteve Longerbeam 	if (ret)
206519a81c14SSteve Longerbeam 		return ret;
206619a81c14SSteve Longerbeam 
206719a81c14SSteve Longerbeam 	/* turn off night mode for capture */
206819a81c14SSteve Longerbeam 	ret = ov5640_set_night_mode(sensor);
206919a81c14SSteve Longerbeam 	if (ret < 0)
207019a81c14SSteve Longerbeam 		return ret;
207119a81c14SSteve Longerbeam 
207219a81c14SSteve Longerbeam 	/* Write capture setting */
2073e4359019SJacopo Mondi 	ov5640_load_regs(sensor, mode->reg_data, mode->reg_data_size);
2074e4359019SJacopo Mondi 	ret = ov5640_set_timings(sensor, mode);
207519a81c14SSteve Longerbeam 	if (ret < 0)
207619a81c14SSteve Longerbeam 		return ret;
207719a81c14SSteve Longerbeam 
207819a81c14SSteve Longerbeam 	/* read capture VTS */
207919a81c14SSteve Longerbeam 	ret = ov5640_get_vts(sensor);
208019a81c14SSteve Longerbeam 	if (ret < 0)
208119a81c14SSteve Longerbeam 		return ret;
208219a81c14SSteve Longerbeam 	cap_vts = ret;
208319a81c14SSteve Longerbeam 	ret = ov5640_get_hts(sensor);
208419a81c14SSteve Longerbeam 	if (ret < 0)
208519a81c14SSteve Longerbeam 		return ret;
208619a81c14SSteve Longerbeam 	if (ret == 0)
208719a81c14SSteve Longerbeam 		return -EINVAL;
208819a81c14SSteve Longerbeam 	cap_hts = ret;
208919a81c14SSteve Longerbeam 
209019a81c14SSteve Longerbeam 	ret = ov5640_get_sysclk(sensor);
209119a81c14SSteve Longerbeam 	if (ret < 0)
209219a81c14SSteve Longerbeam 		return ret;
209319a81c14SSteve Longerbeam 	if (ret == 0)
209419a81c14SSteve Longerbeam 		return -EINVAL;
209519a81c14SSteve Longerbeam 	cap_sysclk = ret;
209619a81c14SSteve Longerbeam 
209719a81c14SSteve Longerbeam 	/* calculate capture banding filter */
209819a81c14SSteve Longerbeam 	ret = ov5640_get_light_freq(sensor);
209919a81c14SSteve Longerbeam 	if (ret < 0)
210019a81c14SSteve Longerbeam 		return ret;
210119a81c14SSteve Longerbeam 	light_freq = ret;
210219a81c14SSteve Longerbeam 
210319a81c14SSteve Longerbeam 	if (light_freq == 60) {
210419a81c14SSteve Longerbeam 		/* 60Hz */
210519a81c14SSteve Longerbeam 		cap_bandfilt = cap_sysclk * 100 / cap_hts * 100 / 120;
210619a81c14SSteve Longerbeam 	} else {
210719a81c14SSteve Longerbeam 		/* 50Hz */
210819a81c14SSteve Longerbeam 		cap_bandfilt = cap_sysclk * 100 / cap_hts;
210919a81c14SSteve Longerbeam 	}
211019a81c14SSteve Longerbeam 
211119a81c14SSteve Longerbeam 	if (!sensor->prev_sysclk) {
211219a81c14SSteve Longerbeam 		ret = ov5640_get_sysclk(sensor);
211319a81c14SSteve Longerbeam 		if (ret < 0)
211419a81c14SSteve Longerbeam 			return ret;
211519a81c14SSteve Longerbeam 		if (ret == 0)
211619a81c14SSteve Longerbeam 			return -EINVAL;
211719a81c14SSteve Longerbeam 		sensor->prev_sysclk = ret;
211819a81c14SSteve Longerbeam 	}
211919a81c14SSteve Longerbeam 
212019a81c14SSteve Longerbeam 	if (!cap_bandfilt)
212119a81c14SSteve Longerbeam 		return -EINVAL;
212219a81c14SSteve Longerbeam 
212319a81c14SSteve Longerbeam 	cap_maxband = (int)((cap_vts - 4) / cap_bandfilt);
212419a81c14SSteve Longerbeam 
212519a81c14SSteve Longerbeam 	/* calculate capture shutter/gain16 */
212619a81c14SSteve Longerbeam 	if (average > sensor->ae_low && average < sensor->ae_high) {
212719a81c14SSteve Longerbeam 		/* in stable range */
212819a81c14SSteve Longerbeam 		cap_gain16_shutter =
212919a81c14SSteve Longerbeam 			prev_gain16 * prev_shutter *
213019a81c14SSteve Longerbeam 			cap_sysclk / sensor->prev_sysclk *
213119a81c14SSteve Longerbeam 			sensor->prev_hts / cap_hts *
213219a81c14SSteve Longerbeam 			sensor->ae_target / average;
213319a81c14SSteve Longerbeam 	} else {
213419a81c14SSteve Longerbeam 		cap_gain16_shutter =
213519a81c14SSteve Longerbeam 			prev_gain16 * prev_shutter *
213619a81c14SSteve Longerbeam 			cap_sysclk / sensor->prev_sysclk *
213719a81c14SSteve Longerbeam 			sensor->prev_hts / cap_hts;
213819a81c14SSteve Longerbeam 	}
213919a81c14SSteve Longerbeam 
214019a81c14SSteve Longerbeam 	/* gain to shutter */
214119a81c14SSteve Longerbeam 	if (cap_gain16_shutter < (cap_bandfilt * 16)) {
214219a81c14SSteve Longerbeam 		/* shutter < 1/100 */
214319a81c14SSteve Longerbeam 		cap_shutter = cap_gain16_shutter / 16;
214419a81c14SSteve Longerbeam 		if (cap_shutter < 1)
214519a81c14SSteve Longerbeam 			cap_shutter = 1;
214619a81c14SSteve Longerbeam 
214719a81c14SSteve Longerbeam 		cap_gain16 = cap_gain16_shutter / cap_shutter;
214819a81c14SSteve Longerbeam 		if (cap_gain16 < 16)
214919a81c14SSteve Longerbeam 			cap_gain16 = 16;
215019a81c14SSteve Longerbeam 	} else {
215119a81c14SSteve Longerbeam 		if (cap_gain16_shutter > (cap_bandfilt * cap_maxband * 16)) {
215219a81c14SSteve Longerbeam 			/* exposure reach max */
215319a81c14SSteve Longerbeam 			cap_shutter = cap_bandfilt * cap_maxband;
215419a81c14SSteve Longerbeam 			if (!cap_shutter)
215519a81c14SSteve Longerbeam 				return -EINVAL;
215619a81c14SSteve Longerbeam 
215719a81c14SSteve Longerbeam 			cap_gain16 = cap_gain16_shutter / cap_shutter;
215819a81c14SSteve Longerbeam 		} else {
215919a81c14SSteve Longerbeam 			/* 1/100 < (cap_shutter = n/100) =< max */
216019a81c14SSteve Longerbeam 			cap_shutter =
216119a81c14SSteve Longerbeam 				((int)(cap_gain16_shutter / 16 / cap_bandfilt))
216219a81c14SSteve Longerbeam 				* cap_bandfilt;
216319a81c14SSteve Longerbeam 			if (!cap_shutter)
216419a81c14SSteve Longerbeam 				return -EINVAL;
216519a81c14SSteve Longerbeam 
216619a81c14SSteve Longerbeam 			cap_gain16 = cap_gain16_shutter / cap_shutter;
216719a81c14SSteve Longerbeam 		}
216819a81c14SSteve Longerbeam 	}
216919a81c14SSteve Longerbeam 
217019a81c14SSteve Longerbeam 	/* set capture gain */
21713cca8ef5SHugues Fruchet 	ret = ov5640_set_gain(sensor, cap_gain16);
217219a81c14SSteve Longerbeam 	if (ret)
217319a81c14SSteve Longerbeam 		return ret;
217419a81c14SSteve Longerbeam 
217519a81c14SSteve Longerbeam 	/* write capture shutter */
217619a81c14SSteve Longerbeam 	if (cap_shutter > (cap_vts - 4)) {
217719a81c14SSteve Longerbeam 		cap_vts = cap_shutter + 4;
217819a81c14SSteve Longerbeam 		ret = ov5640_set_vts(sensor, cap_vts);
217919a81c14SSteve Longerbeam 		if (ret < 0)
218019a81c14SSteve Longerbeam 			return ret;
218119a81c14SSteve Longerbeam 	}
218219a81c14SSteve Longerbeam 
218319a81c14SSteve Longerbeam 	/* set exposure */
21843cca8ef5SHugues Fruchet 	return ov5640_set_exposure(sensor, cap_shutter);
218519a81c14SSteve Longerbeam }
218619a81c14SSteve Longerbeam 
218719a81c14SSteve Longerbeam /*
218819a81c14SSteve Longerbeam  * if sensor changes inside scaling or subsampling
218919a81c14SSteve Longerbeam  * change mode directly
219019a81c14SSteve Longerbeam  */
219119a81c14SSteve Longerbeam static int ov5640_set_mode_direct(struct ov5640_dev *sensor,
21923cca8ef5SHugues Fruchet 				  const struct ov5640_mode_info *mode)
219319a81c14SSteve Longerbeam {
219441d8d7f5SHugues Fruchet 	if (!mode->reg_data)
219519a81c14SSteve Longerbeam 		return -EINVAL;
219619a81c14SSteve Longerbeam 
219719a81c14SSteve Longerbeam 	/* Write capture setting */
2198e4359019SJacopo Mondi 	ov5640_load_regs(sensor, mode->reg_data, mode->reg_data_size);
2199e4359019SJacopo Mondi 	return ov5640_set_timings(sensor, mode);
220019a81c14SSteve Longerbeam }
220119a81c14SSteve Longerbeam 
2202985cdcb0SHugues Fruchet static int ov5640_set_mode(struct ov5640_dev *sensor)
220319a81c14SSteve Longerbeam {
220419a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode = sensor->current_mode;
2205985cdcb0SHugues Fruchet 	const struct ov5640_mode_info *orig_mode = sensor->last_mode;
220619a81c14SSteve Longerbeam 	enum ov5640_downsize_mode dn_mode, orig_dn_mode;
22073cca8ef5SHugues Fruchet 	bool auto_gain = sensor->ctrls.auto_gain->val == 1;
2208dc29a1c1SHugues Fruchet 	bool auto_exp =  sensor->ctrls.auto_exp->val == V4L2_EXPOSURE_AUTO;
220919a81c14SSteve Longerbeam 	int ret;
221019a81c14SSteve Longerbeam 
221119a81c14SSteve Longerbeam 	dn_mode = mode->dn_mode;
221219a81c14SSteve Longerbeam 	orig_dn_mode = orig_mode->dn_mode;
221319a81c14SSteve Longerbeam 
221419a81c14SSteve Longerbeam 	/* auto gain and exposure must be turned off when changing modes */
22153cca8ef5SHugues Fruchet 	if (auto_gain) {
22163cca8ef5SHugues Fruchet 		ret = ov5640_set_autogain(sensor, false);
221719a81c14SSteve Longerbeam 		if (ret)
221819a81c14SSteve Longerbeam 			return ret;
22193cca8ef5SHugues Fruchet 	}
2220bf4a4b51SMaxime Ripard 
22213cca8ef5SHugues Fruchet 	if (auto_exp) {
2222dc29a1c1SHugues Fruchet 		ret = ov5640_set_autoexposure(sensor, false);
222319a81c14SSteve Longerbeam 		if (ret)
22243cca8ef5SHugues Fruchet 			goto restore_auto_gain;
22253cca8ef5SHugues Fruchet 	}
222619a81c14SSteve Longerbeam 
22276c957ed7SJacopo Mondi 	if (ov5640_is_csi2(sensor))
22286c957ed7SJacopo Mondi 		ret = ov5640_set_mipi_pclk(sensor);
22296c957ed7SJacopo Mondi 	else
22306c957ed7SJacopo Mondi 		ret = ov5640_set_dvp_pclk(sensor);
2231aa288248SMaxime Ripard 	if (ret < 0)
2232aa288248SMaxime Ripard 		return 0;
2233aa288248SMaxime Ripard 
223419a81c14SSteve Longerbeam 	if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) ||
223519a81c14SSteve Longerbeam 	    (dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) {
223619a81c14SSteve Longerbeam 		/*
223719a81c14SSteve Longerbeam 		 * change between subsampling and scaling
22383cca8ef5SHugues Fruchet 		 * go through exposure calculation
223919a81c14SSteve Longerbeam 		 */
224019a81c14SSteve Longerbeam 		ret = ov5640_set_mode_exposure_calc(sensor, mode);
224119a81c14SSteve Longerbeam 	} else {
224219a81c14SSteve Longerbeam 		/*
224319a81c14SSteve Longerbeam 		 * change inside subsampling or scaling
224419a81c14SSteve Longerbeam 		 * download firmware directly
224519a81c14SSteve Longerbeam 		 */
22463cca8ef5SHugues Fruchet 		ret = ov5640_set_mode_direct(sensor, mode);
224719a81c14SSteve Longerbeam 	}
224819a81c14SSteve Longerbeam 	if (ret < 0)
22493cca8ef5SHugues Fruchet 		goto restore_auto_exp_gain;
22503cca8ef5SHugues Fruchet 
22513cca8ef5SHugues Fruchet 	/* restore auto gain and exposure */
22523cca8ef5SHugues Fruchet 	if (auto_gain)
22533cca8ef5SHugues Fruchet 		ov5640_set_autogain(sensor, true);
22543cca8ef5SHugues Fruchet 	if (auto_exp)
22553cca8ef5SHugues Fruchet 		ov5640_set_autoexposure(sensor, true);
225619a81c14SSteve Longerbeam 
2257ce85705aSHugues Fruchet 	ret = ov5640_set_binning(sensor, dn_mode != SCALING);
2258ce85705aSHugues Fruchet 	if (ret < 0)
2259ce85705aSHugues Fruchet 		return ret;
226019a81c14SSteve Longerbeam 	ret = ov5640_set_ae_target(sensor, sensor->ae_target);
226119a81c14SSteve Longerbeam 	if (ret < 0)
226219a81c14SSteve Longerbeam 		return ret;
226319a81c14SSteve Longerbeam 	ret = ov5640_get_light_freq(sensor);
226419a81c14SSteve Longerbeam 	if (ret < 0)
226519a81c14SSteve Longerbeam 		return ret;
226619a81c14SSteve Longerbeam 	ret = ov5640_set_bandingfilter(sensor);
226719a81c14SSteve Longerbeam 	if (ret < 0)
226819a81c14SSteve Longerbeam 		return ret;
226919a81c14SSteve Longerbeam 	ret = ov5640_set_virtual_channel(sensor);
227019a81c14SSteve Longerbeam 	if (ret < 0)
227119a81c14SSteve Longerbeam 		return ret;
227219a81c14SSteve Longerbeam 
227319a81c14SSteve Longerbeam 	sensor->pending_mode_change = false;
2274985cdcb0SHugues Fruchet 	sensor->last_mode = mode;
227519a81c14SSteve Longerbeam 
227619a81c14SSteve Longerbeam 	return 0;
22773cca8ef5SHugues Fruchet 
22783cca8ef5SHugues Fruchet restore_auto_exp_gain:
22793cca8ef5SHugues Fruchet 	if (auto_exp)
22803cca8ef5SHugues Fruchet 		ov5640_set_autoexposure(sensor, true);
22813cca8ef5SHugues Fruchet restore_auto_gain:
22823cca8ef5SHugues Fruchet 	if (auto_gain)
22833cca8ef5SHugues Fruchet 		ov5640_set_autogain(sensor, true);
22843cca8ef5SHugues Fruchet 
22853cca8ef5SHugues Fruchet 	return ret;
228619a81c14SSteve Longerbeam }
228719a81c14SSteve Longerbeam 
228819ad26f9SAkinobu Mita static int ov5640_set_framefmt(struct ov5640_dev *sensor,
228919ad26f9SAkinobu Mita 			       struct v4l2_mbus_framefmt *format);
229019ad26f9SAkinobu Mita 
229119a81c14SSteve Longerbeam /* restore the last set video mode after chip power-on */
229219a81c14SSteve Longerbeam static int ov5640_restore_mode(struct ov5640_dev *sensor)
229319a81c14SSteve Longerbeam {
229419a81c14SSteve Longerbeam 	int ret;
229519a81c14SSteve Longerbeam 
229619a81c14SSteve Longerbeam 	/* first load the initial register values */
2297e4359019SJacopo Mondi 	ov5640_load_regs(sensor, ov5640_init_setting,
2298e4359019SJacopo Mondi 			 ARRAY_SIZE(ov5640_init_setting));
229919a81c14SSteve Longerbeam 
23008f57c2f8SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
23017851fe7aSMaxime Ripard 			     (ilog2(OV5640_SCLK2X_ROOT_DIV) << 2) |
23027851fe7aSMaxime Ripard 			     ilog2(OV5640_SCLK_ROOT_DIV));
23038f57c2f8SMaxime Ripard 	if (ret)
23048f57c2f8SMaxime Ripard 		return ret;
23058f57c2f8SMaxime Ripard 
230619a81c14SSteve Longerbeam 	/* now restore the last capture mode */
2307985cdcb0SHugues Fruchet 	ret = ov5640_set_mode(sensor);
230819ad26f9SAkinobu Mita 	if (ret < 0)
230919ad26f9SAkinobu Mita 		return ret;
231019ad26f9SAkinobu Mita 
231119ad26f9SAkinobu Mita 	return ov5640_set_framefmt(sensor, &sensor->fmt);
231219a81c14SSteve Longerbeam }
231319a81c14SSteve Longerbeam 
231419a81c14SSteve Longerbeam static void ov5640_power(struct ov5640_dev *sensor, bool enable)
231519a81c14SSteve Longerbeam {
23161fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->pwdn_gpio, enable ? 0 : 1);
231719a81c14SSteve Longerbeam }
231819a81c14SSteve Longerbeam 
231919a81c14SSteve Longerbeam static void ov5640_reset(struct ov5640_dev *sensor)
232019a81c14SSteve Longerbeam {
232119a81c14SSteve Longerbeam 	if (!sensor->reset_gpio)
232219a81c14SSteve Longerbeam 		return;
232319a81c14SSteve Longerbeam 
23241fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 0);
232519a81c14SSteve Longerbeam 
232619a81c14SSteve Longerbeam 	/* camera power cycle */
232719a81c14SSteve Longerbeam 	ov5640_power(sensor, false);
232819a81c14SSteve Longerbeam 	usleep_range(5000, 10000);
232919a81c14SSteve Longerbeam 	ov5640_power(sensor, true);
233019a81c14SSteve Longerbeam 	usleep_range(5000, 10000);
233119a81c14SSteve Longerbeam 
23321fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 1);
233319a81c14SSteve Longerbeam 	usleep_range(1000, 2000);
233419a81c14SSteve Longerbeam 
23351fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 0);
23361d4c41f3SLoic Poulain 	usleep_range(20000, 25000);
233719a81c14SSteve Longerbeam }
233819a81c14SSteve Longerbeam 
23390f7acb52SHugues Fruchet static int ov5640_set_power_on(struct ov5640_dev *sensor)
234019a81c14SSteve Longerbeam {
23410f7acb52SHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
23420f7acb52SHugues Fruchet 	int ret;
234319a81c14SSteve Longerbeam 
23440f7acb52SHugues Fruchet 	ret = clk_prepare_enable(sensor->xclk);
23450f7acb52SHugues Fruchet 	if (ret) {
23460f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to enable clock\n",
23470f7acb52SHugues Fruchet 			__func__);
23480f7acb52SHugues Fruchet 		return ret;
23490f7acb52SHugues Fruchet 	}
235019a81c14SSteve Longerbeam 
235119a81c14SSteve Longerbeam 	ret = regulator_bulk_enable(OV5640_NUM_SUPPLIES,
235219a81c14SSteve Longerbeam 				    sensor->supplies);
23530f7acb52SHugues Fruchet 	if (ret) {
23540f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to enable regulators\n",
23550f7acb52SHugues Fruchet 			__func__);
235619a81c14SSteve Longerbeam 		goto xclk_off;
23570f7acb52SHugues Fruchet 	}
235819a81c14SSteve Longerbeam 
235919a81c14SSteve Longerbeam 	ov5640_reset(sensor);
236019a81c14SSteve Longerbeam 	ov5640_power(sensor, true);
236119a81c14SSteve Longerbeam 
236219a81c14SSteve Longerbeam 	ret = ov5640_init_slave_id(sensor);
236319a81c14SSteve Longerbeam 	if (ret)
236419a81c14SSteve Longerbeam 		goto power_off;
236519a81c14SSteve Longerbeam 
23660f7acb52SHugues Fruchet 	return 0;
23670f7acb52SHugues Fruchet 
23680f7acb52SHugues Fruchet power_off:
23690f7acb52SHugues Fruchet 	ov5640_power(sensor, false);
23700f7acb52SHugues Fruchet 	regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies);
23710f7acb52SHugues Fruchet xclk_off:
23720f7acb52SHugues Fruchet 	clk_disable_unprepare(sensor->xclk);
23730f7acb52SHugues Fruchet 	return ret;
23740f7acb52SHugues Fruchet }
23750f7acb52SHugues Fruchet 
23760f7acb52SHugues Fruchet static void ov5640_set_power_off(struct ov5640_dev *sensor)
23770f7acb52SHugues Fruchet {
23780f7acb52SHugues Fruchet 	ov5640_power(sensor, false);
23790f7acb52SHugues Fruchet 	regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies);
23800f7acb52SHugues Fruchet 	clk_disable_unprepare(sensor->xclk);
23810f7acb52SHugues Fruchet }
23820f7acb52SHugues Fruchet 
2383b1751ae6SLad Prabhakar static int ov5640_set_power_mipi(struct ov5640_dev *sensor, bool on)
2384b1751ae6SLad Prabhakar {
2385b1751ae6SLad Prabhakar 	int ret;
2386b1751ae6SLad Prabhakar 
2387b1751ae6SLad Prabhakar 	if (!on) {
2388b1751ae6SLad Prabhakar 		/* Reset MIPI bus settings to their default values. */
2389b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
2390b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x04);
2391b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x00);
2392b1751ae6SLad Prabhakar 		return 0;
2393b1751ae6SLad Prabhakar 	}
2394b1751ae6SLad Prabhakar 
2395b1751ae6SLad Prabhakar 	/*
2396b1751ae6SLad Prabhakar 	 * Power up MIPI HS Tx and LS Rx; 2 data lanes mode
2397b1751ae6SLad Prabhakar 	 *
2398b1751ae6SLad Prabhakar 	 * 0x300e = 0x40
2399b1751ae6SLad Prabhakar 	 * [7:5] = 010	: 2 data lanes mode (see FIXME note in
2400b1751ae6SLad Prabhakar 	 *		  "ov5640_set_stream_mipi()")
2401b1751ae6SLad Prabhakar 	 * [4] = 0	: Power up MIPI HS Tx
2402b1751ae6SLad Prabhakar 	 * [3] = 0	: Power up MIPI LS Rx
2403b1751ae6SLad Prabhakar 	 * [2] = 0	: MIPI interface disabled
2404b1751ae6SLad Prabhakar 	 */
2405b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x40);
2406b1751ae6SLad Prabhakar 	if (ret)
2407b1751ae6SLad Prabhakar 		return ret;
2408b1751ae6SLad Prabhakar 
2409b1751ae6SLad Prabhakar 	/*
2410b1751ae6SLad Prabhakar 	 * Gate clock and set LP11 in 'no packets mode' (idle)
2411b1751ae6SLad Prabhakar 	 *
2412b1751ae6SLad Prabhakar 	 * 0x4800 = 0x24
2413b1751ae6SLad Prabhakar 	 * [5] = 1	: Gate clock when 'no packets'
2414b1751ae6SLad Prabhakar 	 * [2] = 1	: MIPI bus in LP11 when 'no packets'
2415b1751ae6SLad Prabhakar 	 */
2416b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x24);
2417b1751ae6SLad Prabhakar 	if (ret)
2418b1751ae6SLad Prabhakar 		return ret;
2419b1751ae6SLad Prabhakar 
2420b1751ae6SLad Prabhakar 	/*
2421b1751ae6SLad Prabhakar 	 * Set data lanes and clock in LP11 when 'sleeping'
2422b1751ae6SLad Prabhakar 	 *
2423b1751ae6SLad Prabhakar 	 * 0x3019 = 0x70
2424b1751ae6SLad Prabhakar 	 * [6] = 1	: MIPI data lane 2 in LP11 when 'sleeping'
2425b1751ae6SLad Prabhakar 	 * [5] = 1	: MIPI data lane 1 in LP11 when 'sleeping'
2426b1751ae6SLad Prabhakar 	 * [4] = 1	: MIPI clock lane in LP11 when 'sleeping'
2427b1751ae6SLad Prabhakar 	 */
2428b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x70);
2429b1751ae6SLad Prabhakar 	if (ret)
2430b1751ae6SLad Prabhakar 		return ret;
2431b1751ae6SLad Prabhakar 
2432b1751ae6SLad Prabhakar 	/* Give lanes some time to coax into LP11 state. */
2433b1751ae6SLad Prabhakar 	usleep_range(500, 1000);
2434b1751ae6SLad Prabhakar 
2435b1751ae6SLad Prabhakar 	return 0;
2436b1751ae6SLad Prabhakar }
2437b1751ae6SLad Prabhakar 
2438576f5d4bSLad Prabhakar static int ov5640_set_power_dvp(struct ov5640_dev *sensor, bool on)
2439576f5d4bSLad Prabhakar {
2440311a6408SLad Prabhakar 	unsigned int flags = sensor->ep.bus.parallel.flags;
244168579b32SHugues Fruchet 	bool bt656 = sensor->ep.bus_type == V4L2_MBUS_BT656;
244268579b32SHugues Fruchet 	u8 polarities = 0;
2443576f5d4bSLad Prabhakar 	int ret;
2444576f5d4bSLad Prabhakar 
2445576f5d4bSLad Prabhakar 	if (!on) {
2446576f5d4bSLad Prabhakar 		/* Reset settings to their default values. */
244768579b32SHugues Fruchet 		ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00, 0x00);
2448311a6408SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
2449311a6408SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, 0x20);
2450576f5d4bSLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01, 0x00);
2451576f5d4bSLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0x00);
2452576f5d4bSLad Prabhakar 		return 0;
2453576f5d4bSLad Prabhakar 	}
2454576f5d4bSLad Prabhakar 
2455576f5d4bSLad Prabhakar 	/*
2456311a6408SLad Prabhakar 	 * Note about parallel port configuration.
2457311a6408SLad Prabhakar 	 *
2458311a6408SLad Prabhakar 	 * When configured in parallel mode, the OV5640 will
2459311a6408SLad Prabhakar 	 * output 10 bits data on DVP data lines [9:0].
2460311a6408SLad Prabhakar 	 * If only 8 bits data are wanted, the 8 bits data lines
2461311a6408SLad Prabhakar 	 * of the camera interface must be physically connected
2462311a6408SLad Prabhakar 	 * on the DVP data lines [9:2].
2463311a6408SLad Prabhakar 	 *
2464311a6408SLad Prabhakar 	 * Control lines polarity can be configured through
2465311a6408SLad Prabhakar 	 * devicetree endpoint control lines properties.
2466311a6408SLad Prabhakar 	 * If no endpoint control lines properties are set,
2467311a6408SLad Prabhakar 	 * polarity will be as below:
2468311a6408SLad Prabhakar 	 * - VSYNC:	active high
2469311a6408SLad Prabhakar 	 * - HREF:	active low
2470311a6408SLad Prabhakar 	 * - PCLK:	active low
247168579b32SHugues Fruchet 	 *
247268579b32SHugues Fruchet 	 * VSYNC & HREF are not configured if BT656 bus mode is selected
2473311a6408SLad Prabhakar 	 */
247468579b32SHugues Fruchet 
247568579b32SHugues Fruchet 	/*
247668579b32SHugues Fruchet 	 * BT656 embedded synchronization configuration
247768579b32SHugues Fruchet 	 *
247868579b32SHugues Fruchet 	 * CCIR656 CTRL00
247968579b32SHugues Fruchet 	 * - [7]:	SYNC code selection (0: auto generate sync code,
248068579b32SHugues Fruchet 	 *		1: sync code from regs 0x4732-0x4735)
248168579b32SHugues Fruchet 	 * - [6]:	f value in CCIR656 SYNC code when fixed f value
248268579b32SHugues Fruchet 	 * - [5]:	Fixed f value
248368579b32SHugues Fruchet 	 * - [4:3]:	Blank toggle data options (00: data=1'h040/1'h200,
248468579b32SHugues Fruchet 	 *		01: data from regs 0x4736-0x4738, 10: always keep 0)
248568579b32SHugues Fruchet 	 * - [1]:	Clip data disable
248668579b32SHugues Fruchet 	 * - [0]:	CCIR656 mode enable
248768579b32SHugues Fruchet 	 *
248868579b32SHugues Fruchet 	 * Default CCIR656 SAV/EAV mode with default codes
248968579b32SHugues Fruchet 	 * SAV=0xff000080 & EAV=0xff00009d is enabled here with settings:
249068579b32SHugues Fruchet 	 * - CCIR656 mode enable
249168579b32SHugues Fruchet 	 * - auto generation of sync codes
249268579b32SHugues Fruchet 	 * - blank toggle data 1'h040/1'h200
249368579b32SHugues Fruchet 	 * - clip reserved data (0x00 & 0xff changed to 0x01 & 0xfe)
249468579b32SHugues Fruchet 	 */
249568579b32SHugues Fruchet 	ret = ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00,
249668579b32SHugues Fruchet 			       bt656 ? 0x01 : 0x00);
249768579b32SHugues Fruchet 	if (ret)
249868579b32SHugues Fruchet 		return ret;
249968579b32SHugues Fruchet 
2500311a6408SLad Prabhakar 	/*
2501311a6408SLad Prabhakar 	 * configure parallel port control lines polarity
2502311a6408SLad Prabhakar 	 *
2503311a6408SLad Prabhakar 	 * POLARITY CTRL0
2504311a6408SLad Prabhakar 	 * - [5]:	PCLK polarity (0: active low, 1: active high)
2505311a6408SLad Prabhakar 	 * - [1]:	HREF polarity (0: active low, 1: active high)
2506311a6408SLad Prabhakar 	 * - [0]:	VSYNC polarity (mismatch here between
2507311a6408SLad Prabhakar 	 *		datasheet and hardware, 0 is active high
2508311a6408SLad Prabhakar 	 *		and 1 is active low...)
2509311a6408SLad Prabhakar 	 */
251068579b32SHugues Fruchet 	if (!bt656) {
2511311a6408SLad Prabhakar 		if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
251268579b32SHugues Fruchet 			polarities |= BIT(1);
2513311a6408SLad Prabhakar 		if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
251468579b32SHugues Fruchet 			polarities |= BIT(0);
251568579b32SHugues Fruchet 	}
251668579b32SHugues Fruchet 	if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
251768579b32SHugues Fruchet 		polarities |= BIT(5);
2518311a6408SLad Prabhakar 
251968579b32SHugues Fruchet 	ret = ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, polarities);
2520311a6408SLad Prabhakar 	if (ret)
2521311a6408SLad Prabhakar 		return ret;
2522311a6408SLad Prabhakar 
2523311a6408SLad Prabhakar 	/*
252468579b32SHugues Fruchet 	 * powerdown MIPI TX/RX PHY & enable DVP
2525311a6408SLad Prabhakar 	 *
2526311a6408SLad Prabhakar 	 * MIPI CONTROL 00
252768579b32SHugues Fruchet 	 * [4] = 1	: Power down MIPI HS Tx
252868579b32SHugues Fruchet 	 * [3] = 1	: Power down MIPI LS Rx
252968579b32SHugues Fruchet 	 * [2] = 0	: DVP enable (MIPI disable)
2530311a6408SLad Prabhakar 	 */
2531311a6408SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x18);
2532311a6408SLad Prabhakar 	if (ret)
2533311a6408SLad Prabhakar 		return ret;
2534311a6408SLad Prabhakar 
2535311a6408SLad Prabhakar 	/*
2536576f5d4bSLad Prabhakar 	 * enable VSYNC/HREF/PCLK DVP control lines
2537576f5d4bSLad Prabhakar 	 * & D[9:6] DVP data lines
2538576f5d4bSLad Prabhakar 	 *
2539576f5d4bSLad Prabhakar 	 * PAD OUTPUT ENABLE 01
2540576f5d4bSLad Prabhakar 	 * - 6:		VSYNC output enable
2541576f5d4bSLad Prabhakar 	 * - 5:		HREF output enable
2542576f5d4bSLad Prabhakar 	 * - 4:		PCLK output enable
2543576f5d4bSLad Prabhakar 	 * - [3:0]:	D[9:6] output enable
2544576f5d4bSLad Prabhakar 	 */
25454039b037SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01,
254668579b32SHugues Fruchet 			       bt656 ? 0x1f : 0x7f);
2547576f5d4bSLad Prabhakar 	if (ret)
2548576f5d4bSLad Prabhakar 		return ret;
2549576f5d4bSLad Prabhakar 
2550576f5d4bSLad Prabhakar 	/*
2551576f5d4bSLad Prabhakar 	 * enable D[5:0] DVP data lines
2552576f5d4bSLad Prabhakar 	 *
2553576f5d4bSLad Prabhakar 	 * PAD OUTPUT ENABLE 02
2554576f5d4bSLad Prabhakar 	 * - [7:2]:	D[5:0] output enable
2555576f5d4bSLad Prabhakar 	 */
2556576f5d4bSLad Prabhakar 	return ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0xfc);
2557576f5d4bSLad Prabhakar }
2558576f5d4bSLad Prabhakar 
25590f7acb52SHugues Fruchet static int ov5640_set_power(struct ov5640_dev *sensor, bool on)
25600f7acb52SHugues Fruchet {
25610f7acb52SHugues Fruchet 	int ret = 0;
25620f7acb52SHugues Fruchet 
25630f7acb52SHugues Fruchet 	if (on) {
25640f7acb52SHugues Fruchet 		ret = ov5640_set_power_on(sensor);
25650f7acb52SHugues Fruchet 		if (ret)
25660f7acb52SHugues Fruchet 			return ret;
25670f7acb52SHugues Fruchet 
256819a81c14SSteve Longerbeam 		ret = ov5640_restore_mode(sensor);
256919a81c14SSteve Longerbeam 		if (ret)
257019a81c14SSteve Longerbeam 			goto power_off;
2571b1751ae6SLad Prabhakar 	}
257219a81c14SSteve Longerbeam 
2573576f5d4bSLad Prabhakar 	if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY)
2574b1751ae6SLad Prabhakar 		ret = ov5640_set_power_mipi(sensor, on);
2575576f5d4bSLad Prabhakar 	else
2576576f5d4bSLad Prabhakar 		ret = ov5640_set_power_dvp(sensor, on);
2577b1751ae6SLad Prabhakar 	if (ret)
2578b1751ae6SLad Prabhakar 		goto power_off;
2579aa4bb8b8SJacopo Mondi 
2580b1751ae6SLad Prabhakar 	if (!on)
2581aa4bb8b8SJacopo Mondi 		ov5640_set_power_off(sensor);
258219a81c14SSteve Longerbeam 
258319a81c14SSteve Longerbeam 	return 0;
258419a81c14SSteve Longerbeam 
258519a81c14SSteve Longerbeam power_off:
25860f7acb52SHugues Fruchet 	ov5640_set_power_off(sensor);
258719a81c14SSteve Longerbeam 	return ret;
258819a81c14SSteve Longerbeam }
258919a81c14SSteve Longerbeam 
259019a81c14SSteve Longerbeam /* --------------- Subdev Operations --------------- */
259119a81c14SSteve Longerbeam 
259219a81c14SSteve Longerbeam static int ov5640_s_power(struct v4l2_subdev *sd, int on)
259319a81c14SSteve Longerbeam {
259419a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
259519a81c14SSteve Longerbeam 	int ret = 0;
259619a81c14SSteve Longerbeam 
259719a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
259819a81c14SSteve Longerbeam 
259919a81c14SSteve Longerbeam 	/*
260019a81c14SSteve Longerbeam 	 * If the power count is modified from 0 to != 0 or from != 0 to 0,
260119a81c14SSteve Longerbeam 	 * update the power state.
260219a81c14SSteve Longerbeam 	 */
260319a81c14SSteve Longerbeam 	if (sensor->power_count == !on) {
260419a81c14SSteve Longerbeam 		ret = ov5640_set_power(sensor, !!on);
260519a81c14SSteve Longerbeam 		if (ret)
260619a81c14SSteve Longerbeam 			goto out;
260719a81c14SSteve Longerbeam 	}
260819a81c14SSteve Longerbeam 
260919a81c14SSteve Longerbeam 	/* Update the power count. */
261019a81c14SSteve Longerbeam 	sensor->power_count += on ? 1 : -1;
261119a81c14SSteve Longerbeam 	WARN_ON(sensor->power_count < 0);
261219a81c14SSteve Longerbeam out:
261319a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
261419a81c14SSteve Longerbeam 
261519a81c14SSteve Longerbeam 	if (on && !ret && sensor->power_count == 1) {
261619a81c14SSteve Longerbeam 		/* restore controls */
261719a81c14SSteve Longerbeam 		ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
261819a81c14SSteve Longerbeam 	}
261919a81c14SSteve Longerbeam 
262019a81c14SSteve Longerbeam 	return ret;
262119a81c14SSteve Longerbeam }
262219a81c14SSteve Longerbeam 
262319a81c14SSteve Longerbeam static int ov5640_try_frame_interval(struct ov5640_dev *sensor,
262419a81c14SSteve Longerbeam 				     struct v4l2_fract *fi,
262519a81c14SSteve Longerbeam 				     u32 width, u32 height)
262619a81c14SSteve Longerbeam {
262719a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
26286530a5ebSJagan Teki 	enum ov5640_frame_rate rate = OV5640_15_FPS;
2629f6cc192fSMaxime Ripard 	int minfps, maxfps, best_fps, fps;
2630f6cc192fSMaxime Ripard 	int i;
263119a81c14SSteve Longerbeam 
263219a81c14SSteve Longerbeam 	minfps = ov5640_framerates[OV5640_15_FPS];
2633e823fb16SMaxime Ripard 	maxfps = ov5640_framerates[OV5640_60_FPS];
263419a81c14SSteve Longerbeam 
263519a81c14SSteve Longerbeam 	if (fi->numerator == 0) {
263619a81c14SSteve Longerbeam 		fi->denominator = maxfps;
263719a81c14SSteve Longerbeam 		fi->numerator = 1;
2638e823fb16SMaxime Ripard 		rate = OV5640_60_FPS;
2639e823fb16SMaxime Ripard 		goto find_mode;
264019a81c14SSteve Longerbeam 	}
264119a81c14SSteve Longerbeam 
2642f6cc192fSMaxime Ripard 	fps = clamp_val(DIV_ROUND_CLOSEST(fi->denominator, fi->numerator),
2643f6cc192fSMaxime Ripard 			minfps, maxfps);
2644f6cc192fSMaxime Ripard 
2645f6cc192fSMaxime Ripard 	best_fps = minfps;
2646f6cc192fSMaxime Ripard 	for (i = 0; i < ARRAY_SIZE(ov5640_framerates); i++) {
2647f6cc192fSMaxime Ripard 		int curr_fps = ov5640_framerates[i];
2648f6cc192fSMaxime Ripard 
2649f6cc192fSMaxime Ripard 		if (abs(curr_fps - fps) < abs(best_fps - fps)) {
2650f6cc192fSMaxime Ripard 			best_fps = curr_fps;
2651f6cc192fSMaxime Ripard 			rate = i;
2652f6cc192fSMaxime Ripard 		}
2653f6cc192fSMaxime Ripard 	}
265419a81c14SSteve Longerbeam 
265519a81c14SSteve Longerbeam 	fi->numerator = 1;
2656f6cc192fSMaxime Ripard 	fi->denominator = best_fps;
265719a81c14SSteve Longerbeam 
2658e823fb16SMaxime Ripard find_mode:
2659b6ae5022SJacopo Mondi 	mode = ov5640_find_mode(sensor, width, height, false);
26605a3ad937SMaxime Ripard 	return mode ? rate : -EINVAL;
266119a81c14SSteve Longerbeam }
266219a81c14SSteve Longerbeam 
266319a81c14SSteve Longerbeam static int ov5640_get_fmt(struct v4l2_subdev *sd,
26640d346d2aSTomi Valkeinen 			  struct v4l2_subdev_state *sd_state,
266519a81c14SSteve Longerbeam 			  struct v4l2_subdev_format *format)
266619a81c14SSteve Longerbeam {
266719a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
266819a81c14SSteve Longerbeam 	struct v4l2_mbus_framefmt *fmt;
266919a81c14SSteve Longerbeam 
267019a81c14SSteve Longerbeam 	if (format->pad != 0)
267119a81c14SSteve Longerbeam 		return -EINVAL;
267219a81c14SSteve Longerbeam 
267319a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
267419a81c14SSteve Longerbeam 
267519a81c14SSteve Longerbeam 	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
26760d346d2aSTomi Valkeinen 		fmt = v4l2_subdev_get_try_format(&sensor->sd, sd_state,
267719a81c14SSteve Longerbeam 						 format->pad);
267819a81c14SSteve Longerbeam 	else
267919a81c14SSteve Longerbeam 		fmt = &sensor->fmt;
268019a81c14SSteve Longerbeam 
268119a81c14SSteve Longerbeam 	format->format = *fmt;
268219a81c14SSteve Longerbeam 
268319a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
268419a81c14SSteve Longerbeam 
268519a81c14SSteve Longerbeam 	return 0;
268619a81c14SSteve Longerbeam }
268719a81c14SSteve Longerbeam 
268819a81c14SSteve Longerbeam static int ov5640_try_fmt_internal(struct v4l2_subdev *sd,
268919a81c14SSteve Longerbeam 				   struct v4l2_mbus_framefmt *fmt,
269019a81c14SSteve Longerbeam 				   enum ov5640_frame_rate fr,
269119a81c14SSteve Longerbeam 				   const struct ov5640_mode_info **new_mode)
269219a81c14SSteve Longerbeam {
269319a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
269419a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
2695e3ee691dSHugues Fruchet 	int i;
269619a81c14SSteve Longerbeam 
2697b6ae5022SJacopo Mondi 	mode = ov5640_find_mode(sensor, fmt->width, fmt->height, true);
269819a81c14SSteve Longerbeam 	if (!mode)
269919a81c14SSteve Longerbeam 		return -EINVAL;
27005113d5b3SJacopo Mondi 	fmt->width = mode->width;
27015113d5b3SJacopo Mondi 	fmt->height = mode->height;
270219a81c14SSteve Longerbeam 
270319a81c14SSteve Longerbeam 	if (new_mode)
270419a81c14SSteve Longerbeam 		*new_mode = mode;
2705e3ee691dSHugues Fruchet 
2706e3ee691dSHugues Fruchet 	for (i = 0; i < ARRAY_SIZE(ov5640_formats); i++)
2707e3ee691dSHugues Fruchet 		if (ov5640_formats[i].code == fmt->code)
2708e3ee691dSHugues Fruchet 			break;
2709e3ee691dSHugues Fruchet 	if (i >= ARRAY_SIZE(ov5640_formats))
2710e6441fdeSHugues Fruchet 		i = 0;
2711e6441fdeSHugues Fruchet 
2712e6441fdeSHugues Fruchet 	fmt->code = ov5640_formats[i].code;
2713e6441fdeSHugues Fruchet 	fmt->colorspace = ov5640_formats[i].colorspace;
2714e6441fdeSHugues Fruchet 	fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
2715e6441fdeSHugues Fruchet 	fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
2716e6441fdeSHugues Fruchet 	fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
2717e3ee691dSHugues Fruchet 
271819a81c14SSteve Longerbeam 	return 0;
271919a81c14SSteve Longerbeam }
272019a81c14SSteve Longerbeam 
27213c28588fSJacopo Mondi static int ov5640_update_pixel_rate(struct ov5640_dev *sensor)
27223c28588fSJacopo Mondi {
27233c28588fSJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
27243c28588fSJacopo Mondi 	enum ov5640_pixel_rate_id pixel_rate_id = mode->pixel_rate;
27253c28588fSJacopo Mondi 	struct v4l2_mbus_framefmt *fmt = &sensor->fmt;
272632979f67SJacopo Mondi 	const struct ov5640_timings *timings;
2727bce93b82SJacopo Mondi 	s32 exposure_val, exposure_max;
272832979f67SJacopo Mondi 	unsigned int hblank;
27293c28588fSJacopo Mondi 	unsigned int i = 0;
27303c28588fSJacopo Mondi 	u32 pixel_rate;
27313c28588fSJacopo Mondi 	s64 link_freq;
27323c28588fSJacopo Mondi 	u32 num_lanes;
273319f2e3e6SHugues Fruchet 	u32 vblank;
27343c28588fSJacopo Mondi 	u32 bpp;
27353c28588fSJacopo Mondi 
27363c28588fSJacopo Mondi 	/*
27373c28588fSJacopo Mondi 	 * Update the pixel rate control value.
27383c28588fSJacopo Mondi 	 *
27393c28588fSJacopo Mondi 	 * For DVP mode, maintain the pixel rate calculation using fixed FPS.
27403c28588fSJacopo Mondi 	 */
27413c28588fSJacopo Mondi 	if (!ov5640_is_csi2(sensor)) {
27423c28588fSJacopo Mondi 		__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate,
27433c28588fSJacopo Mondi 					 ov5640_calc_pixel_rate(sensor));
27443c28588fSJacopo Mondi 
27453c28588fSJacopo Mondi 		return 0;
27463c28588fSJacopo Mondi 	}
27473c28588fSJacopo Mondi 
27483c28588fSJacopo Mondi 	/*
27493c28588fSJacopo Mondi 	 * The MIPI CSI-2 link frequency should comply with the CSI-2
27503c28588fSJacopo Mondi 	 * specification and be lower than 1GHz.
27513c28588fSJacopo Mondi 	 *
27523c28588fSJacopo Mondi 	 * Start from the suggested pixel_rate for the current mode and
27533c28588fSJacopo Mondi 	 * progressively slow it down if it exceeds 1GHz.
27543c28588fSJacopo Mondi 	 */
27553c28588fSJacopo Mondi 	num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes;
27563c28588fSJacopo Mondi 	bpp = ov5640_code_to_bpp(fmt->code);
27573c28588fSJacopo Mondi 	do {
27583c28588fSJacopo Mondi 		pixel_rate = ov5640_pixel_rates[pixel_rate_id];
27593c28588fSJacopo Mondi 		link_freq = pixel_rate * bpp / (2 * num_lanes);
27603c28588fSJacopo Mondi 	} while (link_freq >= 1000000000U &&
27613c28588fSJacopo Mondi 		 ++pixel_rate_id < OV5640_NUM_PIXEL_RATES);
27623c28588fSJacopo Mondi 
27633c28588fSJacopo Mondi 	sensor->current_link_freq = link_freq;
27643c28588fSJacopo Mondi 
27653c28588fSJacopo Mondi 	/*
27663c28588fSJacopo Mondi 	 * Higher link rates require the clock tree to be programmed with
27673c28588fSJacopo Mondi 	 * 'mipi_div' = 1; this has the effect of halving the actual output
27683c28588fSJacopo Mondi 	 * pixel rate in the MIPI domain.
27693c28588fSJacopo Mondi 	 *
27703c28588fSJacopo Mondi 	 * Adjust the pixel rate and link frequency control value to report it
27713c28588fSJacopo Mondi 	 * correctly to userspace.
27723c28588fSJacopo Mondi 	 */
27733c28588fSJacopo Mondi 	if (link_freq > OV5640_LINK_RATE_MAX) {
27743c28588fSJacopo Mondi 		pixel_rate /= 2;
27753c28588fSJacopo Mondi 		link_freq /= 2;
27763c28588fSJacopo Mondi 	}
27773c28588fSJacopo Mondi 
27783c28588fSJacopo Mondi 	for (i = 0; i < ARRAY_SIZE(ov5640_csi2_link_freqs); ++i) {
27793c28588fSJacopo Mondi 		if (ov5640_csi2_link_freqs[i] == link_freq)
27803c28588fSJacopo Mondi 			break;
27813c28588fSJacopo Mondi 	}
27823c28588fSJacopo Mondi 	WARN_ON(i == ARRAY_SIZE(ov5640_csi2_link_freqs));
27833c28588fSJacopo Mondi 
27843c28588fSJacopo Mondi 	__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, pixel_rate);
27853c28588fSJacopo Mondi 	__v4l2_ctrl_s_ctrl(sensor->ctrls.link_freq, i);
27863c28588fSJacopo Mondi 
278732979f67SJacopo Mondi 	timings = ov5640_timings(sensor, mode);
278832979f67SJacopo Mondi 	hblank = timings->htot - mode->width;
278932979f67SJacopo Mondi 	__v4l2_ctrl_modify_range(sensor->ctrls.hblank,
279032979f67SJacopo Mondi 				 hblank, hblank, 1, hblank);
279132979f67SJacopo Mondi 
279219f2e3e6SHugues Fruchet 	vblank = timings->vblank_def;
2793bce93b82SJacopo Mondi 
279419f2e3e6SHugues Fruchet 	if (sensor->current_fr != mode->def_fps) {
279519f2e3e6SHugues Fruchet 		/*
279619f2e3e6SHugues Fruchet 		 * Compute the vertical blanking according to the framerate
279719f2e3e6SHugues Fruchet 		 * configured with s_frame_interval.
279819f2e3e6SHugues Fruchet 		 */
279919f2e3e6SHugues Fruchet 		int fie_num = sensor->frame_interval.numerator;
280019f2e3e6SHugues Fruchet 		int fie_denom = sensor->frame_interval.denominator;
280119f2e3e6SHugues Fruchet 
280219f2e3e6SHugues Fruchet 		vblank = ((fie_num * pixel_rate / fie_denom) / timings->htot) -
280319f2e3e6SHugues Fruchet 			mode->height;
280419f2e3e6SHugues Fruchet 	}
280519f2e3e6SHugues Fruchet 
280619f2e3e6SHugues Fruchet 	__v4l2_ctrl_modify_range(sensor->ctrls.vblank, OV5640_MIN_VBLANK,
280719f2e3e6SHugues Fruchet 				 OV5640_MAX_VTS - mode->height, 1, vblank);
280819f2e3e6SHugues Fruchet 	__v4l2_ctrl_s_ctrl(sensor->ctrls.vblank, vblank);
280919f2e3e6SHugues Fruchet 
281019f2e3e6SHugues Fruchet 	exposure_max = timings->crop.height + vblank - 4;
2811bce93b82SJacopo Mondi 	exposure_val = clamp_t(s32, sensor->ctrls.exposure->val,
2812bce93b82SJacopo Mondi 			       sensor->ctrls.exposure->minimum,
2813bce93b82SJacopo Mondi 			       exposure_max);
281419f2e3e6SHugues Fruchet 
2815bce93b82SJacopo Mondi 	__v4l2_ctrl_modify_range(sensor->ctrls.exposure,
2816bce93b82SJacopo Mondi 				 sensor->ctrls.exposure->minimum,
2817bce93b82SJacopo Mondi 				 exposure_max, 1, exposure_val);
2818bce93b82SJacopo Mondi 
28193c28588fSJacopo Mondi 	return 0;
28203c28588fSJacopo Mondi }
28213c28588fSJacopo Mondi 
282219a81c14SSteve Longerbeam static int ov5640_set_fmt(struct v4l2_subdev *sd,
28230d346d2aSTomi Valkeinen 			  struct v4l2_subdev_state *sd_state,
282419a81c14SSteve Longerbeam 			  struct v4l2_subdev_format *format)
282519a81c14SSteve Longerbeam {
282619a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
282719a81c14SSteve Longerbeam 	const struct ov5640_mode_info *new_mode;
2828e6441fdeSHugues Fruchet 	struct v4l2_mbus_framefmt *mbus_fmt = &format->format;
282919a81c14SSteve Longerbeam 	int ret;
283019a81c14SSteve Longerbeam 
283119a81c14SSteve Longerbeam 	if (format->pad != 0)
283219a81c14SSteve Longerbeam 		return -EINVAL;
283319a81c14SSteve Longerbeam 
283419a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
283519a81c14SSteve Longerbeam 
283619a81c14SSteve Longerbeam 	if (sensor->streaming) {
283719a81c14SSteve Longerbeam 		ret = -EBUSY;
283819a81c14SSteve Longerbeam 		goto out;
283919a81c14SSteve Longerbeam 	}
284019a81c14SSteve Longerbeam 
2841e6441fdeSHugues Fruchet 	ret = ov5640_try_fmt_internal(sd, mbus_fmt,
284219a81c14SSteve Longerbeam 				      sensor->current_fr, &new_mode);
284319a81c14SSteve Longerbeam 	if (ret)
284419a81c14SSteve Longerbeam 		goto out;
284519a81c14SSteve Longerbeam 
2846e738f5ddSMirela Rabulea 	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
2847e738f5ddSMirela Rabulea 		*v4l2_subdev_get_try_format(sd, sd_state, 0) = *mbus_fmt;
2848e738f5ddSMirela Rabulea 		goto out;
2849e738f5ddSMirela Rabulea 	}
285019a81c14SSteve Longerbeam 
28516949d864SHugues Fruchet 	if (new_mode != sensor->current_mode) {
285219f2e3e6SHugues Fruchet 		sensor->current_fr = new_mode->def_fps;
285319a81c14SSteve Longerbeam 		sensor->current_mode = new_mode;
285419a81c14SSteve Longerbeam 		sensor->pending_mode_change = true;
28556949d864SHugues Fruchet 	}
285607115449SJacopo Mondi 	if (mbus_fmt->code != sensor->fmt.code)
2857fb98e29fSHugues Fruchet 		sensor->pending_fmt_change = true;
285807115449SJacopo Mondi 
2859e738f5ddSMirela Rabulea 	/* update format even if code is unchanged, resolution might change */
2860e738f5ddSMirela Rabulea 	sensor->fmt = *mbus_fmt;
2861e738f5ddSMirela Rabulea 
28623c28588fSJacopo Mondi 	ov5640_update_pixel_rate(sensor);
28633c28588fSJacopo Mondi 
286419a81c14SSteve Longerbeam out:
286519a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
286619a81c14SSteve Longerbeam 	return ret;
286719a81c14SSteve Longerbeam }
286819a81c14SSteve Longerbeam 
2869e3ee691dSHugues Fruchet static int ov5640_set_framefmt(struct ov5640_dev *sensor,
2870e3ee691dSHugues Fruchet 			       struct v4l2_mbus_framefmt *format)
2871e3ee691dSHugues Fruchet {
2872e3ee691dSHugues Fruchet 	int ret = 0;
2873d47c4126SHugues Fruchet 	bool is_jpeg = false;
2874b7ed3abdSLoic Poulain 	u8 fmt, mux;
2875e3ee691dSHugues Fruchet 
2876e3ee691dSHugues Fruchet 	switch (format->code) {
28771536fbdbSXavier Roumegue 	case MEDIA_BUS_FMT_UYVY8_1X16:
2878e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_UYVY8_2X8:
2879e3ee691dSHugues Fruchet 		/* YUV422, UYVY */
2880b7ed3abdSLoic Poulain 		fmt = 0x3f;
2881b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_YUV422;
2882e3ee691dSHugues Fruchet 		break;
28831536fbdbSXavier Roumegue 	case MEDIA_BUS_FMT_YUYV8_1X16:
2884e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_YUYV8_2X8:
2885e3ee691dSHugues Fruchet 		/* YUV422, YUYV */
2886b7ed3abdSLoic Poulain 		fmt = 0x30;
2887b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_YUV422;
2888e3ee691dSHugues Fruchet 		break;
2889e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_RGB565_2X8_LE:
2890e3ee691dSHugues Fruchet 		/* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */
2891b7ed3abdSLoic Poulain 		fmt = 0x6F;
2892b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RGB;
2893e3ee691dSHugues Fruchet 		break;
2894e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_RGB565_2X8_BE:
2895e3ee691dSHugues Fruchet 		/* RGB565 {r[4:0],g[5:3]},{g[2:0],b[4:0]} */
2896b7ed3abdSLoic Poulain 		fmt = 0x61;
2897b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RGB;
2898e3ee691dSHugues Fruchet 		break;
2899d47c4126SHugues Fruchet 	case MEDIA_BUS_FMT_JPEG_1X8:
2900d47c4126SHugues Fruchet 		/* YUV422, YUYV */
2901b7ed3abdSLoic Poulain 		fmt = 0x30;
2902b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_YUV422;
2903d47c4126SHugues Fruchet 		is_jpeg = true;
2904d47c4126SHugues Fruchet 		break;
2905b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SBGGR8_1X8:
2906b7ed3abdSLoic Poulain 		/* Raw, BGBG... / GRGR... */
2907b7ed3abdSLoic Poulain 		fmt = 0x00;
2908b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2909b7ed3abdSLoic Poulain 		break;
2910b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SGBRG8_1X8:
2911b7ed3abdSLoic Poulain 		/* Raw bayer, GBGB... / RGRG... */
2912b7ed3abdSLoic Poulain 		fmt = 0x01;
2913b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2914b7ed3abdSLoic Poulain 		break;
2915b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SGRBG8_1X8:
2916b7ed3abdSLoic Poulain 		/* Raw bayer, GRGR... / BGBG... */
2917b7ed3abdSLoic Poulain 		fmt = 0x02;
2918b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2919b7ed3abdSLoic Poulain 		break;
2920b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SRGGB8_1X8:
2921b7ed3abdSLoic Poulain 		/* Raw bayer, RGRG... / GBGB... */
2922b7ed3abdSLoic Poulain 		fmt = 0x03;
2923b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2924b7ed3abdSLoic Poulain 		break;
2925e3ee691dSHugues Fruchet 	default:
2926e3ee691dSHugues Fruchet 		return -EINVAL;
2927e3ee691dSHugues Fruchet 	}
2928e3ee691dSHugues Fruchet 
2929e3ee691dSHugues Fruchet 	/* FORMAT CONTROL00: YUV and RGB formatting */
2930b7ed3abdSLoic Poulain 	ret = ov5640_write_reg(sensor, OV5640_REG_FORMAT_CONTROL00, fmt);
2931e3ee691dSHugues Fruchet 	if (ret)
2932e3ee691dSHugues Fruchet 		return ret;
2933e3ee691dSHugues Fruchet 
2934e3ee691dSHugues Fruchet 	/* FORMAT MUX CONTROL: ISP YUV or RGB */
2935b7ed3abdSLoic Poulain 	ret = ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL, mux);
2936d47c4126SHugues Fruchet 	if (ret)
2937d47c4126SHugues Fruchet 		return ret;
2938d47c4126SHugues Fruchet 
2939d47c4126SHugues Fruchet 	/*
2940d47c4126SHugues Fruchet 	 * TIMING TC REG21:
2941d47c4126SHugues Fruchet 	 * - [5]:	JPEG enable
2942d47c4126SHugues Fruchet 	 */
2943d47c4126SHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
2944d47c4126SHugues Fruchet 			     BIT(5), is_jpeg ? BIT(5) : 0);
2945d47c4126SHugues Fruchet 	if (ret)
2946d47c4126SHugues Fruchet 		return ret;
2947d47c4126SHugues Fruchet 
2948d47c4126SHugues Fruchet 	/*
2949d47c4126SHugues Fruchet 	 * SYSTEM RESET02:
2950d47c4126SHugues Fruchet 	 * - [4]:	Reset JFIFO
2951d47c4126SHugues Fruchet 	 * - [3]:	Reset SFIFO
2952d47c4126SHugues Fruchet 	 * - [2]:	Reset JPEG
2953d47c4126SHugues Fruchet 	 */
2954d47c4126SHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_RESET02,
2955d47c4126SHugues Fruchet 			     BIT(4) | BIT(3) | BIT(2),
2956d47c4126SHugues Fruchet 			     is_jpeg ? 0 : (BIT(4) | BIT(3) | BIT(2)));
2957d47c4126SHugues Fruchet 	if (ret)
2958d47c4126SHugues Fruchet 		return ret;
2959d47c4126SHugues Fruchet 
2960d47c4126SHugues Fruchet 	/*
2961d47c4126SHugues Fruchet 	 * CLOCK ENABLE02:
2962d47c4126SHugues Fruchet 	 * - [5]:	Enable JPEG 2x clock
2963d47c4126SHugues Fruchet 	 * - [3]:	Enable JPEG clock
2964d47c4126SHugues Fruchet 	 */
2965d47c4126SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_SYS_CLOCK_ENABLE02,
2966d47c4126SHugues Fruchet 			      BIT(5) | BIT(3),
2967d47c4126SHugues Fruchet 			      is_jpeg ? (BIT(5) | BIT(3)) : 0);
2968e3ee691dSHugues Fruchet }
296919a81c14SSteve Longerbeam 
297019a81c14SSteve Longerbeam /*
297119a81c14SSteve Longerbeam  * Sensor Controls.
297219a81c14SSteve Longerbeam  */
297319a81c14SSteve Longerbeam 
297419a81c14SSteve Longerbeam static int ov5640_set_ctrl_hue(struct ov5640_dev *sensor, int value)
297519a81c14SSteve Longerbeam {
297619a81c14SSteve Longerbeam 	int ret;
297719a81c14SSteve Longerbeam 
297819a81c14SSteve Longerbeam 	if (value) {
297919a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
298019a81c14SSteve Longerbeam 				     BIT(0), BIT(0));
298119a81c14SSteve Longerbeam 		if (ret)
298219a81c14SSteve Longerbeam 			return ret;
298319a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_SDE_CTRL1, value);
298419a81c14SSteve Longerbeam 	} else {
298519a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(0), 0);
298619a81c14SSteve Longerbeam 	}
298719a81c14SSteve Longerbeam 
298819a81c14SSteve Longerbeam 	return ret;
298919a81c14SSteve Longerbeam }
299019a81c14SSteve Longerbeam 
299119a81c14SSteve Longerbeam static int ov5640_set_ctrl_contrast(struct ov5640_dev *sensor, int value)
299219a81c14SSteve Longerbeam {
299319a81c14SSteve Longerbeam 	int ret;
299419a81c14SSteve Longerbeam 
299519a81c14SSteve Longerbeam 	if (value) {
299619a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
299719a81c14SSteve Longerbeam 				     BIT(2), BIT(2));
299819a81c14SSteve Longerbeam 		if (ret)
299919a81c14SSteve Longerbeam 			return ret;
300019a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL5,
300119a81c14SSteve Longerbeam 				       value & 0xff);
300219a81c14SSteve Longerbeam 	} else {
300319a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(2), 0);
300419a81c14SSteve Longerbeam 	}
300519a81c14SSteve Longerbeam 
300619a81c14SSteve Longerbeam 	return ret;
300719a81c14SSteve Longerbeam }
300819a81c14SSteve Longerbeam 
300919a81c14SSteve Longerbeam static int ov5640_set_ctrl_saturation(struct ov5640_dev *sensor, int value)
301019a81c14SSteve Longerbeam {
301119a81c14SSteve Longerbeam 	int ret;
301219a81c14SSteve Longerbeam 
301319a81c14SSteve Longerbeam 	if (value) {
301419a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
301519a81c14SSteve Longerbeam 				     BIT(1), BIT(1));
301619a81c14SSteve Longerbeam 		if (ret)
301719a81c14SSteve Longerbeam 			return ret;
301819a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL3,
301919a81c14SSteve Longerbeam 				       value & 0xff);
302019a81c14SSteve Longerbeam 		if (ret)
302119a81c14SSteve Longerbeam 			return ret;
302219a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL4,
302319a81c14SSteve Longerbeam 				       value & 0xff);
302419a81c14SSteve Longerbeam 	} else {
302519a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(1), 0);
302619a81c14SSteve Longerbeam 	}
302719a81c14SSteve Longerbeam 
302819a81c14SSteve Longerbeam 	return ret;
302919a81c14SSteve Longerbeam }
303019a81c14SSteve Longerbeam 
303119a81c14SSteve Longerbeam static int ov5640_set_ctrl_white_balance(struct ov5640_dev *sensor, int awb)
303219a81c14SSteve Longerbeam {
303319a81c14SSteve Longerbeam 	int ret;
303419a81c14SSteve Longerbeam 
303519a81c14SSteve Longerbeam 	ret = ov5640_mod_reg(sensor, OV5640_REG_AWB_MANUAL_CTRL,
303619a81c14SSteve Longerbeam 			     BIT(0), awb ? 0 : 1);
303719a81c14SSteve Longerbeam 	if (ret)
303819a81c14SSteve Longerbeam 		return ret;
303919a81c14SSteve Longerbeam 
304019a81c14SSteve Longerbeam 	if (!awb) {
304119a81c14SSteve Longerbeam 		u16 red = (u16)sensor->ctrls.red_balance->val;
304219a81c14SSteve Longerbeam 		u16 blue = (u16)sensor->ctrls.blue_balance->val;
304319a81c14SSteve Longerbeam 
304419a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_R_GAIN, red);
304519a81c14SSteve Longerbeam 		if (ret)
304619a81c14SSteve Longerbeam 			return ret;
304719a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_B_GAIN, blue);
304819a81c14SSteve Longerbeam 	}
304919a81c14SSteve Longerbeam 
305019a81c14SSteve Longerbeam 	return ret;
305119a81c14SSteve Longerbeam }
305219a81c14SSteve Longerbeam 
30533cca8ef5SHugues Fruchet static int ov5640_set_ctrl_exposure(struct ov5640_dev *sensor,
30543cca8ef5SHugues Fruchet 				    enum v4l2_exposure_auto_type auto_exposure)
305519a81c14SSteve Longerbeam {
305619a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
30573cca8ef5SHugues Fruchet 	bool auto_exp = (auto_exposure == V4L2_EXPOSURE_AUTO);
305819a81c14SSteve Longerbeam 	int ret = 0;
305919a81c14SSteve Longerbeam 
306019a81c14SSteve Longerbeam 	if (ctrls->auto_exp->is_new) {
30613cca8ef5SHugues Fruchet 		ret = ov5640_set_autoexposure(sensor, auto_exp);
306219a81c14SSteve Longerbeam 		if (ret)
306319a81c14SSteve Longerbeam 			return ret;
306419a81c14SSteve Longerbeam 	}
306519a81c14SSteve Longerbeam 
30663cca8ef5SHugues Fruchet 	if (!auto_exp && ctrls->exposure->is_new) {
306719a81c14SSteve Longerbeam 		u16 max_exp;
306819a81c14SSteve Longerbeam 
306919a81c14SSteve Longerbeam 		ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_VTS,
307019a81c14SSteve Longerbeam 					&max_exp);
307119a81c14SSteve Longerbeam 		if (ret)
307219a81c14SSteve Longerbeam 			return ret;
307319a81c14SSteve Longerbeam 		ret = ov5640_get_vts(sensor);
307419a81c14SSteve Longerbeam 		if (ret < 0)
307519a81c14SSteve Longerbeam 			return ret;
307619a81c14SSteve Longerbeam 		max_exp += ret;
30776146fde3SHugues Fruchet 		ret = 0;
307819a81c14SSteve Longerbeam 
307919a81c14SSteve Longerbeam 		if (ctrls->exposure->val < max_exp)
308019a81c14SSteve Longerbeam 			ret = ov5640_set_exposure(sensor, ctrls->exposure->val);
308119a81c14SSteve Longerbeam 	}
308219a81c14SSteve Longerbeam 
308319a81c14SSteve Longerbeam 	return ret;
308419a81c14SSteve Longerbeam }
308519a81c14SSteve Longerbeam 
30863cca8ef5SHugues Fruchet static int ov5640_set_ctrl_gain(struct ov5640_dev *sensor, bool auto_gain)
308719a81c14SSteve Longerbeam {
308819a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
308919a81c14SSteve Longerbeam 	int ret = 0;
309019a81c14SSteve Longerbeam 
309119a81c14SSteve Longerbeam 	if (ctrls->auto_gain->is_new) {
30923cca8ef5SHugues Fruchet 		ret = ov5640_set_autogain(sensor, auto_gain);
309319a81c14SSteve Longerbeam 		if (ret)
309419a81c14SSteve Longerbeam 			return ret;
309519a81c14SSteve Longerbeam 	}
309619a81c14SSteve Longerbeam 
30973cca8ef5SHugues Fruchet 	if (!auto_gain && ctrls->gain->is_new)
30983cca8ef5SHugues Fruchet 		ret = ov5640_set_gain(sensor, ctrls->gain->val);
309919a81c14SSteve Longerbeam 
310019a81c14SSteve Longerbeam 	return ret;
310119a81c14SSteve Longerbeam }
310219a81c14SSteve Longerbeam 
31039f6d7bacSChen-Yu Tsai static const char * const test_pattern_menu[] = {
31049f6d7bacSChen-Yu Tsai 	"Disabled",
31059f6d7bacSChen-Yu Tsai 	"Color bars",
3106bddc5cdfSChen-Yu Tsai 	"Color bars w/ rolling bar",
3107bddc5cdfSChen-Yu Tsai 	"Color squares",
3108bddc5cdfSChen-Yu Tsai 	"Color squares w/ rolling bar",
31099f6d7bacSChen-Yu Tsai };
31109f6d7bacSChen-Yu Tsai 
3111a0c29afbSChen-Yu Tsai #define OV5640_TEST_ENABLE		BIT(7)
3112a0c29afbSChen-Yu Tsai #define OV5640_TEST_ROLLING		BIT(6)	/* rolling horizontal bar */
3113a0c29afbSChen-Yu Tsai #define OV5640_TEST_TRANSPARENT		BIT(5)
3114a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE_BW		BIT(4)	/* black & white squares */
3115a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_STANDARD	(0 << 2)
3116a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_1	(1 << 2)
3117a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_HOR_CHANGE	(2 << 2)
3118a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_2	(3 << 2)
3119a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR			(0 << 0)
3120a0c29afbSChen-Yu Tsai #define OV5640_TEST_RANDOM		(1 << 0)
3121a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE		(2 << 0)
3122a0c29afbSChen-Yu Tsai #define OV5640_TEST_BLACK		(3 << 0)
3123a0c29afbSChen-Yu Tsai 
3124a0c29afbSChen-Yu Tsai static const u8 test_pattern_val[] = {
3125a0c29afbSChen-Yu Tsai 	0,
31262aff1fc3SChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_BAR_VERT_CHANGE_1 |
3127a0c29afbSChen-Yu Tsai 		OV5640_TEST_BAR,
3128bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_ROLLING |
3129bddc5cdfSChen-Yu Tsai 		OV5640_TEST_BAR_VERT_CHANGE_1 | OV5640_TEST_BAR,
3130bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_SQUARE,
3131bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_ROLLING | OV5640_TEST_SQUARE,
3132a0c29afbSChen-Yu Tsai };
3133a0c29afbSChen-Yu Tsai 
313419a81c14SSteve Longerbeam static int ov5640_set_ctrl_test_pattern(struct ov5640_dev *sensor, int value)
313519a81c14SSteve Longerbeam {
3136a0c29afbSChen-Yu Tsai 	return ov5640_write_reg(sensor, OV5640_REG_PRE_ISP_TEST_SET1,
3137a0c29afbSChen-Yu Tsai 				test_pattern_val[value]);
313819a81c14SSteve Longerbeam }
313919a81c14SSteve Longerbeam 
31401068fecaSMylène Josserand static int ov5640_set_ctrl_light_freq(struct ov5640_dev *sensor, int value)
31411068fecaSMylène Josserand {
31421068fecaSMylène Josserand 	int ret;
31431068fecaSMylène Josserand 
31441068fecaSMylène Josserand 	ret = ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL01, BIT(7),
31451068fecaSMylène Josserand 			     (value == V4L2_CID_POWER_LINE_FREQUENCY_AUTO) ?
31461068fecaSMylène Josserand 			     0 : BIT(7));
31471068fecaSMylène Josserand 	if (ret)
31481068fecaSMylène Josserand 		return ret;
31491068fecaSMylène Josserand 
31501068fecaSMylène Josserand 	return ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL00, BIT(2),
31511068fecaSMylène Josserand 			      (value == V4L2_CID_POWER_LINE_FREQUENCY_50HZ) ?
31521068fecaSMylène Josserand 			      BIT(2) : 0);
31531068fecaSMylène Josserand }
31541068fecaSMylène Josserand 
3155ce85705aSHugues Fruchet static int ov5640_set_ctrl_hflip(struct ov5640_dev *sensor, int value)
3156ce85705aSHugues Fruchet {
3157ce85705aSHugues Fruchet 	/*
3158c3f3ba3eSHugues Fruchet 	 * If sensor is mounted upside down, mirror logic is inversed.
3159c3f3ba3eSHugues Fruchet 	 *
3160ce85705aSHugues Fruchet 	 * Sensor is a BSI (Back Side Illuminated) one,
3161ce85705aSHugues Fruchet 	 * so image captured is physically mirrored.
3162ce85705aSHugues Fruchet 	 * This is why mirror logic is inversed in
3163ce85705aSHugues Fruchet 	 * order to cancel this mirror effect.
3164ce85705aSHugues Fruchet 	 */
3165ce85705aSHugues Fruchet 
3166ce85705aSHugues Fruchet 	/*
3167ce85705aSHugues Fruchet 	 * TIMING TC REG21:
3168ce85705aSHugues Fruchet 	 * - [2]:	ISP mirror
3169ce85705aSHugues Fruchet 	 * - [1]:	Sensor mirror
3170ce85705aSHugues Fruchet 	 */
3171ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
3172ce85705aSHugues Fruchet 			      BIT(2) | BIT(1),
3173c3f3ba3eSHugues Fruchet 			      (!(value ^ sensor->upside_down)) ?
3174c3f3ba3eSHugues Fruchet 			      (BIT(2) | BIT(1)) : 0);
3175ce85705aSHugues Fruchet }
3176ce85705aSHugues Fruchet 
3177ce85705aSHugues Fruchet static int ov5640_set_ctrl_vflip(struct ov5640_dev *sensor, int value)
3178ce85705aSHugues Fruchet {
3179c3f3ba3eSHugues Fruchet 	/* If sensor is mounted upside down, flip logic is inversed */
3180c3f3ba3eSHugues Fruchet 
3181ce85705aSHugues Fruchet 	/*
3182ce85705aSHugues Fruchet 	 * TIMING TC REG20:
3183ce85705aSHugues Fruchet 	 * - [2]:	ISP vflip
3184ce85705aSHugues Fruchet 	 * - [1]:	Sensor vflip
3185ce85705aSHugues Fruchet 	 */
3186ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20,
3187ce85705aSHugues Fruchet 			      BIT(2) | BIT(1),
3188c3f3ba3eSHugues Fruchet 			      (value ^ sensor->upside_down) ?
3189c3f3ba3eSHugues Fruchet 			      (BIT(2) | BIT(1)) : 0);
3190ce85705aSHugues Fruchet }
3191ce85705aSHugues Fruchet 
3192bce93b82SJacopo Mondi static int ov5640_set_ctrl_vblank(struct ov5640_dev *sensor, int value)
3193bce93b82SJacopo Mondi {
3194bce93b82SJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
3195bce93b82SJacopo Mondi 
3196bce93b82SJacopo Mondi 	/* Update the VTOT timing register value. */
3197bce93b82SJacopo Mondi 	return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS,
3198bce93b82SJacopo Mondi 				  mode->height + value);
3199bce93b82SJacopo Mondi }
3200bce93b82SJacopo Mondi 
320119a81c14SSteve Longerbeam static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
320219a81c14SSteve Longerbeam {
320319a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
320419a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
320519a81c14SSteve Longerbeam 	int val;
320619a81c14SSteve Longerbeam 
320719a81c14SSteve Longerbeam 	/* v4l2_ctrl_lock() locks our own mutex */
320819a81c14SSteve Longerbeam 
320919a81c14SSteve Longerbeam 	switch (ctrl->id) {
321019a81c14SSteve Longerbeam 	case V4L2_CID_AUTOGAIN:
321119a81c14SSteve Longerbeam 		val = ov5640_get_gain(sensor);
321219a81c14SSteve Longerbeam 		if (val < 0)
321319a81c14SSteve Longerbeam 			return val;
321419a81c14SSteve Longerbeam 		sensor->ctrls.gain->val = val;
321519a81c14SSteve Longerbeam 		break;
321619a81c14SSteve Longerbeam 	case V4L2_CID_EXPOSURE_AUTO:
321719a81c14SSteve Longerbeam 		val = ov5640_get_exposure(sensor);
321819a81c14SSteve Longerbeam 		if (val < 0)
321919a81c14SSteve Longerbeam 			return val;
322019a81c14SSteve Longerbeam 		sensor->ctrls.exposure->val = val;
322119a81c14SSteve Longerbeam 		break;
322219a81c14SSteve Longerbeam 	}
322319a81c14SSteve Longerbeam 
322419a81c14SSteve Longerbeam 	return 0;
322519a81c14SSteve Longerbeam }
322619a81c14SSteve Longerbeam 
322719a81c14SSteve Longerbeam static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl)
322819a81c14SSteve Longerbeam {
322919a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
323019a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
3231bce93b82SJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
3232bce93b82SJacopo Mondi 	const struct ov5640_timings *timings;
3233bce93b82SJacopo Mondi 	unsigned int exp_max;
323419a81c14SSteve Longerbeam 	int ret;
323519a81c14SSteve Longerbeam 
323619a81c14SSteve Longerbeam 	/* v4l2_ctrl_lock() locks our own mutex */
323719a81c14SSteve Longerbeam 
3238bce93b82SJacopo Mondi 	switch (ctrl->id) {
3239bce93b82SJacopo Mondi 	case V4L2_CID_VBLANK:
3240bce93b82SJacopo Mondi 		/* Update the exposure range to the newly programmed vblank. */
3241bce93b82SJacopo Mondi 		timings = ov5640_timings(sensor, mode);
3242bce93b82SJacopo Mondi 		exp_max = mode->height + ctrl->val - 4;
3243bce93b82SJacopo Mondi 		__v4l2_ctrl_modify_range(sensor->ctrls.exposure,
3244bce93b82SJacopo Mondi 					 sensor->ctrls.exposure->minimum,
3245bce93b82SJacopo Mondi 					 exp_max, sensor->ctrls.exposure->step,
3246bce93b82SJacopo Mondi 					 timings->vblank_def);
3247bce93b82SJacopo Mondi 		break;
3248bce93b82SJacopo Mondi 	}
3249bce93b82SJacopo Mondi 
325019a81c14SSteve Longerbeam 	/*
325119a81c14SSteve Longerbeam 	 * If the device is not powered up by the host driver do
325219a81c14SSteve Longerbeam 	 * not apply any controls to H/W at this time. Instead
325319a81c14SSteve Longerbeam 	 * the controls will be restored right after power-up.
325419a81c14SSteve Longerbeam 	 */
325519a81c14SSteve Longerbeam 	if (sensor->power_count == 0)
325619a81c14SSteve Longerbeam 		return 0;
325719a81c14SSteve Longerbeam 
325819a81c14SSteve Longerbeam 	switch (ctrl->id) {
325919a81c14SSteve Longerbeam 	case V4L2_CID_AUTOGAIN:
326019a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_gain(sensor, ctrl->val);
326119a81c14SSteve Longerbeam 		break;
326219a81c14SSteve Longerbeam 	case V4L2_CID_EXPOSURE_AUTO:
326319a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_exposure(sensor, ctrl->val);
326419a81c14SSteve Longerbeam 		break;
326519a81c14SSteve Longerbeam 	case V4L2_CID_AUTO_WHITE_BALANCE:
326619a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_white_balance(sensor, ctrl->val);
326719a81c14SSteve Longerbeam 		break;
326819a81c14SSteve Longerbeam 	case V4L2_CID_HUE:
326919a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_hue(sensor, ctrl->val);
327019a81c14SSteve Longerbeam 		break;
327119a81c14SSteve Longerbeam 	case V4L2_CID_CONTRAST:
327219a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_contrast(sensor, ctrl->val);
327319a81c14SSteve Longerbeam 		break;
327419a81c14SSteve Longerbeam 	case V4L2_CID_SATURATION:
327519a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_saturation(sensor, ctrl->val);
327619a81c14SSteve Longerbeam 		break;
327719a81c14SSteve Longerbeam 	case V4L2_CID_TEST_PATTERN:
327819a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_test_pattern(sensor, ctrl->val);
327919a81c14SSteve Longerbeam 		break;
32801068fecaSMylène Josserand 	case V4L2_CID_POWER_LINE_FREQUENCY:
32811068fecaSMylène Josserand 		ret = ov5640_set_ctrl_light_freq(sensor, ctrl->val);
32821068fecaSMylène Josserand 		break;
3283ce85705aSHugues Fruchet 	case V4L2_CID_HFLIP:
3284ce85705aSHugues Fruchet 		ret = ov5640_set_ctrl_hflip(sensor, ctrl->val);
3285ce85705aSHugues Fruchet 		break;
3286ce85705aSHugues Fruchet 	case V4L2_CID_VFLIP:
3287ce85705aSHugues Fruchet 		ret = ov5640_set_ctrl_vflip(sensor, ctrl->val);
3288ce85705aSHugues Fruchet 		break;
3289bce93b82SJacopo Mondi 	case V4L2_CID_VBLANK:
3290bce93b82SJacopo Mondi 		ret = ov5640_set_ctrl_vblank(sensor, ctrl->val);
3291bce93b82SJacopo Mondi 		break;
329219a81c14SSteve Longerbeam 	default:
329319a81c14SSteve Longerbeam 		ret = -EINVAL;
329419a81c14SSteve Longerbeam 		break;
329519a81c14SSteve Longerbeam 	}
329619a81c14SSteve Longerbeam 
329719a81c14SSteve Longerbeam 	return ret;
329819a81c14SSteve Longerbeam }
329919a81c14SSteve Longerbeam 
330019a81c14SSteve Longerbeam static const struct v4l2_ctrl_ops ov5640_ctrl_ops = {
330119a81c14SSteve Longerbeam 	.g_volatile_ctrl = ov5640_g_volatile_ctrl,
330219a81c14SSteve Longerbeam 	.s_ctrl = ov5640_s_ctrl,
330319a81c14SSteve Longerbeam };
330419a81c14SSteve Longerbeam 
330519a81c14SSteve Longerbeam static int ov5640_init_controls(struct ov5640_dev *sensor)
330619a81c14SSteve Longerbeam {
330722845bf2SJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
330819a81c14SSteve Longerbeam 	const struct v4l2_ctrl_ops *ops = &ov5640_ctrl_ops;
330919a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
331019a81c14SSteve Longerbeam 	struct v4l2_ctrl_handler *hdl = &ctrls->handler;
331132979f67SJacopo Mondi 	const struct ov5640_timings *timings;
3312bce93b82SJacopo Mondi 	unsigned int max_vblank;
331332979f67SJacopo Mondi 	unsigned int hblank;
331419a81c14SSteve Longerbeam 	int ret;
331519a81c14SSteve Longerbeam 
331619a81c14SSteve Longerbeam 	v4l2_ctrl_handler_init(hdl, 32);
331719a81c14SSteve Longerbeam 
331819a81c14SSteve Longerbeam 	/* we can use our own mutex for the ctrl lock */
331919a81c14SSteve Longerbeam 	hdl->lock = &sensor->lock;
332019a81c14SSteve Longerbeam 
3321cc196e48SBenoit Parrot 	/* Clock related controls */
3322cc196e48SBenoit Parrot 	ctrls->pixel_rate = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE,
332322845bf2SJacopo Mondi 			      ov5640_pixel_rates[OV5640_NUM_PIXEL_RATES - 1],
332422845bf2SJacopo Mondi 			      ov5640_pixel_rates[0], 1,
332522845bf2SJacopo Mondi 			      ov5640_pixel_rates[mode->pixel_rate]);
3326cc196e48SBenoit Parrot 
33277a3b8d4bSJacopo Mondi 	ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops,
33287a3b8d4bSJacopo Mondi 					V4L2_CID_LINK_FREQ,
33297a3b8d4bSJacopo Mondi 					ARRAY_SIZE(ov5640_csi2_link_freqs) - 1,
33307a3b8d4bSJacopo Mondi 					OV5640_DEFAULT_LINK_FREQ,
33317a3b8d4bSJacopo Mondi 					ov5640_csi2_link_freqs);
33327a3b8d4bSJacopo Mondi 
333332979f67SJacopo Mondi 	timings = ov5640_timings(sensor, mode);
333432979f67SJacopo Mondi 	hblank = timings->htot - mode->width;
333532979f67SJacopo Mondi 	ctrls->hblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HBLANK, hblank,
333632979f67SJacopo Mondi 					  hblank, 1, hblank);
333732979f67SJacopo Mondi 
3338bce93b82SJacopo Mondi 	max_vblank = OV5640_MAX_VTS - mode->height;
3339bce93b82SJacopo Mondi 	ctrls->vblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VBLANK,
3340bce93b82SJacopo Mondi 					  OV5640_MIN_VBLANK, max_vblank,
3341bce93b82SJacopo Mondi 					  1, timings->vblank_def);
3342bce93b82SJacopo Mondi 
334319a81c14SSteve Longerbeam 	/* Auto/manual white balance */
334419a81c14SSteve Longerbeam 	ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops,
334519a81c14SSteve Longerbeam 					   V4L2_CID_AUTO_WHITE_BALANCE,
334619a81c14SSteve Longerbeam 					   0, 1, 1, 1);
334719a81c14SSteve Longerbeam 	ctrls->blue_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BLUE_BALANCE,
334819a81c14SSteve Longerbeam 						0, 4095, 1, 0);
334919a81c14SSteve Longerbeam 	ctrls->red_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_RED_BALANCE,
335019a81c14SSteve Longerbeam 					       0, 4095, 1, 0);
335119a81c14SSteve Longerbeam 	/* Auto/manual exposure */
335219a81c14SSteve Longerbeam 	ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops,
335319a81c14SSteve Longerbeam 						 V4L2_CID_EXPOSURE_AUTO,
335419a81c14SSteve Longerbeam 						 V4L2_EXPOSURE_MANUAL, 0,
335519a81c14SSteve Longerbeam 						 V4L2_EXPOSURE_AUTO);
335619a81c14SSteve Longerbeam 	ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
335719a81c14SSteve Longerbeam 					    0, 65535, 1, 0);
335819a81c14SSteve Longerbeam 	/* Auto/manual gain */
335919a81c14SSteve Longerbeam 	ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN,
336019a81c14SSteve Longerbeam 					     0, 1, 1, 1);
336119a81c14SSteve Longerbeam 	ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN,
336219a81c14SSteve Longerbeam 					0, 1023, 1, 0);
336319a81c14SSteve Longerbeam 
336419a81c14SSteve Longerbeam 	ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION,
336519a81c14SSteve Longerbeam 					      0, 255, 1, 64);
336619a81c14SSteve Longerbeam 	ctrls->hue = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HUE,
336719a81c14SSteve Longerbeam 				       0, 359, 1, 0);
336819a81c14SSteve Longerbeam 	ctrls->contrast = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST,
336919a81c14SSteve Longerbeam 					    0, 255, 1, 0);
337019a81c14SSteve Longerbeam 	ctrls->test_pattern =
337119a81c14SSteve Longerbeam 		v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN,
337219a81c14SSteve Longerbeam 					     ARRAY_SIZE(test_pattern_menu) - 1,
337319a81c14SSteve Longerbeam 					     0, 0, test_pattern_menu);
3374ce85705aSHugues Fruchet 	ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP,
3375ce85705aSHugues Fruchet 					 0, 1, 1, 0);
3376ce85705aSHugues Fruchet 	ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP,
3377ce85705aSHugues Fruchet 					 0, 1, 1, 0);
337819a81c14SSteve Longerbeam 
33791068fecaSMylène Josserand 	ctrls->light_freq =
33801068fecaSMylène Josserand 		v4l2_ctrl_new_std_menu(hdl, ops,
33811068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY,
33821068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
33831068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
33841068fecaSMylène Josserand 
338519a81c14SSteve Longerbeam 	if (hdl->error) {
338619a81c14SSteve Longerbeam 		ret = hdl->error;
338719a81c14SSteve Longerbeam 		goto free_ctrls;
338819a81c14SSteve Longerbeam 	}
338919a81c14SSteve Longerbeam 
3390cc196e48SBenoit Parrot 	ctrls->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY;
33917a3b8d4bSJacopo Mondi 	ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
339232979f67SJacopo Mondi 	ctrls->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
339319a81c14SSteve Longerbeam 	ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE;
339419a81c14SSteve Longerbeam 	ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE;
339519a81c14SSteve Longerbeam 
339619a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false);
339719a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(2, &ctrls->auto_gain, 0, true);
339819a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(2, &ctrls->auto_exp, 1, true);
339919a81c14SSteve Longerbeam 
340019a81c14SSteve Longerbeam 	sensor->sd.ctrl_handler = hdl;
340119a81c14SSteve Longerbeam 	return 0;
340219a81c14SSteve Longerbeam 
340319a81c14SSteve Longerbeam free_ctrls:
340419a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(hdl);
340519a81c14SSteve Longerbeam 	return ret;
340619a81c14SSteve Longerbeam }
340719a81c14SSteve Longerbeam 
340819a81c14SSteve Longerbeam static int ov5640_enum_frame_size(struct v4l2_subdev *sd,
34090d346d2aSTomi Valkeinen 				  struct v4l2_subdev_state *sd_state,
341019a81c14SSteve Longerbeam 				  struct v4l2_subdev_frame_size_enum *fse)
341119a81c14SSteve Longerbeam {
341219a81c14SSteve Longerbeam 	if (fse->pad != 0)
341319a81c14SSteve Longerbeam 		return -EINVAL;
341419a81c14SSteve Longerbeam 	if (fse->index >= OV5640_NUM_MODES)
341519a81c14SSteve Longerbeam 		return -EINVAL;
341619a81c14SSteve Longerbeam 
34175113d5b3SJacopo Mondi 	fse->min_width = ov5640_mode_data[fse->index].width;
341841d8d7f5SHugues Fruchet 	fse->max_width = fse->min_width;
34195113d5b3SJacopo Mondi 	fse->min_height = ov5640_mode_data[fse->index].height;
342041d8d7f5SHugues Fruchet 	fse->max_height = fse->min_height;
342119a81c14SSteve Longerbeam 
342219a81c14SSteve Longerbeam 	return 0;
342319a81c14SSteve Longerbeam }
342419a81c14SSteve Longerbeam 
342519a81c14SSteve Longerbeam static int ov5640_enum_frame_interval(
342619a81c14SSteve Longerbeam 	struct v4l2_subdev *sd,
34270d346d2aSTomi Valkeinen 	struct v4l2_subdev_state *sd_state,
342819a81c14SSteve Longerbeam 	struct v4l2_subdev_frame_interval_enum *fie)
342919a81c14SSteve Longerbeam {
343019a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
343119a81c14SSteve Longerbeam 	struct v4l2_fract tpf;
343219a81c14SSteve Longerbeam 	int ret;
343319a81c14SSteve Longerbeam 
343419a81c14SSteve Longerbeam 	if (fie->pad != 0)
343519a81c14SSteve Longerbeam 		return -EINVAL;
343619a81c14SSteve Longerbeam 	if (fie->index >= OV5640_NUM_FRAMERATES)
343719a81c14SSteve Longerbeam 		return -EINVAL;
343819a81c14SSteve Longerbeam 
343919a81c14SSteve Longerbeam 	tpf.numerator = 1;
344019a81c14SSteve Longerbeam 	tpf.denominator = ov5640_framerates[fie->index];
344119a81c14SSteve Longerbeam 
344219a81c14SSteve Longerbeam 	ret = ov5640_try_frame_interval(sensor, &tpf,
344319a81c14SSteve Longerbeam 					fie->width, fie->height);
344419a81c14SSteve Longerbeam 	if (ret < 0)
344519a81c14SSteve Longerbeam 		return -EINVAL;
344619a81c14SSteve Longerbeam 
344719a81c14SSteve Longerbeam 	fie->interval = tpf;
344819a81c14SSteve Longerbeam 	return 0;
344919a81c14SSteve Longerbeam }
345019a81c14SSteve Longerbeam 
345119a81c14SSteve Longerbeam static int ov5640_g_frame_interval(struct v4l2_subdev *sd,
345219a81c14SSteve Longerbeam 				   struct v4l2_subdev_frame_interval *fi)
345319a81c14SSteve Longerbeam {
345419a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
345519a81c14SSteve Longerbeam 
345619a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
345719a81c14SSteve Longerbeam 	fi->interval = sensor->frame_interval;
345819a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
345919a81c14SSteve Longerbeam 
346019a81c14SSteve Longerbeam 	return 0;
346119a81c14SSteve Longerbeam }
346219a81c14SSteve Longerbeam 
346319a81c14SSteve Longerbeam static int ov5640_s_frame_interval(struct v4l2_subdev *sd,
346419a81c14SSteve Longerbeam 				   struct v4l2_subdev_frame_interval *fi)
346519a81c14SSteve Longerbeam {
346619a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
346719a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
346819a81c14SSteve Longerbeam 	int frame_rate, ret = 0;
346919a81c14SSteve Longerbeam 
347019a81c14SSteve Longerbeam 	if (fi->pad != 0)
347119a81c14SSteve Longerbeam 		return -EINVAL;
347219a81c14SSteve Longerbeam 
347319a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
347419a81c14SSteve Longerbeam 
347519a81c14SSteve Longerbeam 	if (sensor->streaming) {
347619a81c14SSteve Longerbeam 		ret = -EBUSY;
347719a81c14SSteve Longerbeam 		goto out;
347819a81c14SSteve Longerbeam 	}
347919a81c14SSteve Longerbeam 
348019a81c14SSteve Longerbeam 	mode = sensor->current_mode;
348119a81c14SSteve Longerbeam 
348219a81c14SSteve Longerbeam 	frame_rate = ov5640_try_frame_interval(sensor, &fi->interval,
34835113d5b3SJacopo Mondi 					       mode->width,
34845113d5b3SJacopo Mondi 					       mode->height);
3485e823fb16SMaxime Ripard 	if (frame_rate < 0) {
3486e823fb16SMaxime Ripard 		/* Always return a valid frame interval value */
3487e823fb16SMaxime Ripard 		fi->interval = sensor->frame_interval;
3488e823fb16SMaxime Ripard 		goto out;
3489e823fb16SMaxime Ripard 	}
349019a81c14SSteve Longerbeam 
3491b6ae5022SJacopo Mondi 	mode = ov5640_find_mode(sensor, mode->width, mode->height, true);
34923c4a7372SHugues Fruchet 	if (!mode) {
34933c4a7372SHugues Fruchet 		ret = -EINVAL;
34943c4a7372SHugues Fruchet 		goto out;
34953c4a7372SHugues Fruchet 	}
34963c4a7372SHugues Fruchet 
3497b6ae5022SJacopo Mondi 	if (ov5640_framerates[frame_rate] > ov5640_framerates[mode->max_fps]) {
3498b6ae5022SJacopo Mondi 		ret = -EINVAL;
3499b6ae5022SJacopo Mondi 		goto out;
3500b6ae5022SJacopo Mondi 	}
3501b6ae5022SJacopo Mondi 
35020929983eSHugues Fruchet 	if (mode != sensor->current_mode ||
35030929983eSHugues Fruchet 	    frame_rate != sensor->current_fr) {
35040929983eSHugues Fruchet 		sensor->current_fr = frame_rate;
35050929983eSHugues Fruchet 		sensor->frame_interval = fi->interval;
35063c4a7372SHugues Fruchet 		sensor->current_mode = mode;
350719a81c14SSteve Longerbeam 		sensor->pending_mode_change = true;
3508cc196e48SBenoit Parrot 
350919f2e3e6SHugues Fruchet 		ov5640_update_pixel_rate(sensor);
35106949d864SHugues Fruchet 	}
351119a81c14SSteve Longerbeam out:
351219a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
351319a81c14SSteve Longerbeam 	return ret;
351419a81c14SSteve Longerbeam }
351519a81c14SSteve Longerbeam 
351619a81c14SSteve Longerbeam static int ov5640_enum_mbus_code(struct v4l2_subdev *sd,
35170d346d2aSTomi Valkeinen 				 struct v4l2_subdev_state *sd_state,
351819a81c14SSteve Longerbeam 				 struct v4l2_subdev_mbus_code_enum *code)
351919a81c14SSteve Longerbeam {
352019a81c14SSteve Longerbeam 	if (code->pad != 0)
352119a81c14SSteve Longerbeam 		return -EINVAL;
3522e3ee691dSHugues Fruchet 	if (code->index >= ARRAY_SIZE(ov5640_formats))
352319a81c14SSteve Longerbeam 		return -EINVAL;
352419a81c14SSteve Longerbeam 
3525e3ee691dSHugues Fruchet 	code->code = ov5640_formats[code->index].code;
352619a81c14SSteve Longerbeam 	return 0;
352719a81c14SSteve Longerbeam }
352819a81c14SSteve Longerbeam 
352919a81c14SSteve Longerbeam static int ov5640_s_stream(struct v4l2_subdev *sd, int enable)
353019a81c14SSteve Longerbeam {
353119a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
353219a81c14SSteve Longerbeam 	int ret = 0;
353319a81c14SSteve Longerbeam 
353419a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
353519a81c14SSteve Longerbeam 
353619a81c14SSteve Longerbeam 	if (sensor->streaming == !enable) {
353719a81c14SSteve Longerbeam 		if (enable && sensor->pending_mode_change) {
3538985cdcb0SHugues Fruchet 			ret = ov5640_set_mode(sensor);
353919a81c14SSteve Longerbeam 			if (ret)
354019a81c14SSteve Longerbeam 				goto out;
3541fb98e29fSHugues Fruchet 		}
3542e3ee691dSHugues Fruchet 
3543fb98e29fSHugues Fruchet 		if (enable && sensor->pending_fmt_change) {
3544e3ee691dSHugues Fruchet 			ret = ov5640_set_framefmt(sensor, &sensor->fmt);
3545e3ee691dSHugues Fruchet 			if (ret)
3546e3ee691dSHugues Fruchet 				goto out;
3547fb98e29fSHugues Fruchet 			sensor->pending_fmt_change = false;
354819a81c14SSteve Longerbeam 		}
354919a81c14SSteve Longerbeam 
35508e823f5cSJacopo Mondi 		if (ov5640_is_csi2(sensor))
3551f22996dbSHugues Fruchet 			ret = ov5640_set_stream_mipi(sensor, enable);
3552f22996dbSHugues Fruchet 		else
3553f22996dbSHugues Fruchet 			ret = ov5640_set_stream_dvp(sensor, enable);
3554f22996dbSHugues Fruchet 
355519a81c14SSteve Longerbeam 		if (!ret)
355619a81c14SSteve Longerbeam 			sensor->streaming = enable;
355719a81c14SSteve Longerbeam 	}
355819a81c14SSteve Longerbeam out:
355919a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
356019a81c14SSteve Longerbeam 	return ret;
356119a81c14SSteve Longerbeam }
356219a81c14SSteve Longerbeam 
3563*90b0f355SJacopo Mondi static int ov5640_init_cfg(struct v4l2_subdev *sd,
3564*90b0f355SJacopo Mondi 			   struct v4l2_subdev_state *state)
3565*90b0f355SJacopo Mondi {
3566*90b0f355SJacopo Mondi 	struct v4l2_mbus_framefmt *fmt =
3567*90b0f355SJacopo Mondi 				v4l2_subdev_get_try_format(sd, state, 0);
3568*90b0f355SJacopo Mondi 
3569*90b0f355SJacopo Mondi 	*fmt = ov5640_default_fmt;
3570*90b0f355SJacopo Mondi 
3571*90b0f355SJacopo Mondi 	return 0;
3572*90b0f355SJacopo Mondi }
3573*90b0f355SJacopo Mondi 
357419a81c14SSteve Longerbeam static const struct v4l2_subdev_core_ops ov5640_core_ops = {
357519a81c14SSteve Longerbeam 	.s_power = ov5640_s_power,
35762d18fbc5SAkinobu Mita 	.log_status = v4l2_ctrl_subdev_log_status,
35772d18fbc5SAkinobu Mita 	.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
35782d18fbc5SAkinobu Mita 	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
357919a81c14SSteve Longerbeam };
358019a81c14SSteve Longerbeam 
358119a81c14SSteve Longerbeam static const struct v4l2_subdev_video_ops ov5640_video_ops = {
358219a81c14SSteve Longerbeam 	.g_frame_interval = ov5640_g_frame_interval,
358319a81c14SSteve Longerbeam 	.s_frame_interval = ov5640_s_frame_interval,
358419a81c14SSteve Longerbeam 	.s_stream = ov5640_s_stream,
358519a81c14SSteve Longerbeam };
358619a81c14SSteve Longerbeam 
358719a81c14SSteve Longerbeam static const struct v4l2_subdev_pad_ops ov5640_pad_ops = {
3588*90b0f355SJacopo Mondi 	.init_cfg = ov5640_init_cfg,
358919a81c14SSteve Longerbeam 	.enum_mbus_code = ov5640_enum_mbus_code,
359019a81c14SSteve Longerbeam 	.get_fmt = ov5640_get_fmt,
359119a81c14SSteve Longerbeam 	.set_fmt = ov5640_set_fmt,
359219a81c14SSteve Longerbeam 	.enum_frame_size = ov5640_enum_frame_size,
359319a81c14SSteve Longerbeam 	.enum_frame_interval = ov5640_enum_frame_interval,
359419a81c14SSteve Longerbeam };
359519a81c14SSteve Longerbeam 
359619a81c14SSteve Longerbeam static const struct v4l2_subdev_ops ov5640_subdev_ops = {
359719a81c14SSteve Longerbeam 	.core = &ov5640_core_ops,
359819a81c14SSteve Longerbeam 	.video = &ov5640_video_ops,
359919a81c14SSteve Longerbeam 	.pad = &ov5640_pad_ops,
360019a81c14SSteve Longerbeam };
360119a81c14SSteve Longerbeam 
360219a81c14SSteve Longerbeam static int ov5640_get_regulators(struct ov5640_dev *sensor)
360319a81c14SSteve Longerbeam {
360419a81c14SSteve Longerbeam 	int i;
360519a81c14SSteve Longerbeam 
360619a81c14SSteve Longerbeam 	for (i = 0; i < OV5640_NUM_SUPPLIES; i++)
360719a81c14SSteve Longerbeam 		sensor->supplies[i].supply = ov5640_supply_name[i];
360819a81c14SSteve Longerbeam 
360919a81c14SSteve Longerbeam 	return devm_regulator_bulk_get(&sensor->i2c_client->dev,
361019a81c14SSteve Longerbeam 				       OV5640_NUM_SUPPLIES,
361119a81c14SSteve Longerbeam 				       sensor->supplies);
361219a81c14SSteve Longerbeam }
361319a81c14SSteve Longerbeam 
36140f7acb52SHugues Fruchet static int ov5640_check_chip_id(struct ov5640_dev *sensor)
36150f7acb52SHugues Fruchet {
36160f7acb52SHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
36170f7acb52SHugues Fruchet 	int ret = 0;
36180f7acb52SHugues Fruchet 	u16 chip_id;
36190f7acb52SHugues Fruchet 
36200f7acb52SHugues Fruchet 	ret = ov5640_set_power_on(sensor);
36210f7acb52SHugues Fruchet 	if (ret)
36220f7acb52SHugues Fruchet 		return ret;
36230f7acb52SHugues Fruchet 
36240f7acb52SHugues Fruchet 	ret = ov5640_read_reg16(sensor, OV5640_REG_CHIP_ID, &chip_id);
36250f7acb52SHugues Fruchet 	if (ret) {
36260f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to read chip identifier\n",
36270f7acb52SHugues Fruchet 			__func__);
36280f7acb52SHugues Fruchet 		goto power_off;
36290f7acb52SHugues Fruchet 	}
36300f7acb52SHugues Fruchet 
36310f7acb52SHugues Fruchet 	if (chip_id != 0x5640) {
36320f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: wrong chip identifier, expected 0x5640, got 0x%x\n",
36330f7acb52SHugues Fruchet 			__func__, chip_id);
36340f7acb52SHugues Fruchet 		ret = -ENXIO;
36350f7acb52SHugues Fruchet 	}
36360f7acb52SHugues Fruchet 
36370f7acb52SHugues Fruchet power_off:
36380f7acb52SHugues Fruchet 	ov5640_set_power_off(sensor);
36390f7acb52SHugues Fruchet 	return ret;
36400f7acb52SHugues Fruchet }
36410f7acb52SHugues Fruchet 
3642e6714993SKieran Bingham static int ov5640_probe(struct i2c_client *client)
364319a81c14SSteve Longerbeam {
364419a81c14SSteve Longerbeam 	struct device *dev = &client->dev;
364519a81c14SSteve Longerbeam 	struct fwnode_handle *endpoint;
364619a81c14SSteve Longerbeam 	struct ov5640_dev *sensor;
3647c3f3ba3eSHugues Fruchet 	u32 rotation;
364819a81c14SSteve Longerbeam 	int ret;
364919a81c14SSteve Longerbeam 
365019a81c14SSteve Longerbeam 	sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
365119a81c14SSteve Longerbeam 	if (!sensor)
365219a81c14SSteve Longerbeam 		return -ENOMEM;
365319a81c14SSteve Longerbeam 
365419a81c14SSteve Longerbeam 	sensor->i2c_client = client;
3655fb98e29fSHugues Fruchet 
3656fb98e29fSHugues Fruchet 	/*
3657fb98e29fSHugues Fruchet 	 * default init sequence initialize sensor to
3658fb98e29fSHugues Fruchet 	 * YUV422 UYVY VGA@30fps
3659fb98e29fSHugues Fruchet 	 */
3660*90b0f355SJacopo Mondi 	sensor->fmt = ov5640_default_fmt;
366119a81c14SSteve Longerbeam 	sensor->frame_interval.numerator = 1;
366219a81c14SSteve Longerbeam 	sensor->frame_interval.denominator = ov5640_framerates[OV5640_30_FPS];
366319a81c14SSteve Longerbeam 	sensor->current_fr = OV5640_30_FPS;
366419a81c14SSteve Longerbeam 	sensor->current_mode =
3665086c25f8SMaxime Ripard 		&ov5640_mode_data[OV5640_MODE_VGA_640_480];
3666985cdcb0SHugues Fruchet 	sensor->last_mode = sensor->current_mode;
36673c28588fSJacopo Mondi 	sensor->current_link_freq = OV5640_DEFAULT_LINK_FREQ;
366819a81c14SSteve Longerbeam 
366919a81c14SSteve Longerbeam 	sensor->ae_target = 52;
367019a81c14SSteve Longerbeam 
3671c3f3ba3eSHugues Fruchet 	/* optional indication of physical rotation of sensor */
3672c3f3ba3eSHugues Fruchet 	ret = fwnode_property_read_u32(dev_fwnode(&client->dev), "rotation",
3673c3f3ba3eSHugues Fruchet 				       &rotation);
3674c3f3ba3eSHugues Fruchet 	if (!ret) {
3675c3f3ba3eSHugues Fruchet 		switch (rotation) {
3676c3f3ba3eSHugues Fruchet 		case 180:
3677c3f3ba3eSHugues Fruchet 			sensor->upside_down = true;
36781771e9fbSGustavo A. R. Silva 			fallthrough;
3679c3f3ba3eSHugues Fruchet 		case 0:
3680c3f3ba3eSHugues Fruchet 			break;
3681c3f3ba3eSHugues Fruchet 		default:
3682c3f3ba3eSHugues Fruchet 			dev_warn(dev, "%u degrees rotation is not supported, ignoring...\n",
3683c3f3ba3eSHugues Fruchet 				 rotation);
3684c3f3ba3eSHugues Fruchet 		}
3685c3f3ba3eSHugues Fruchet 	}
3686c3f3ba3eSHugues Fruchet 
3687ce96bcf5SSakari Ailus 	endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev),
3688ce96bcf5SSakari Ailus 						  NULL);
368919a81c14SSteve Longerbeam 	if (!endpoint) {
369019a81c14SSteve Longerbeam 		dev_err(dev, "endpoint node not found\n");
369119a81c14SSteve Longerbeam 		return -EINVAL;
369219a81c14SSteve Longerbeam 	}
369319a81c14SSteve Longerbeam 
369419a81c14SSteve Longerbeam 	ret = v4l2_fwnode_endpoint_parse(endpoint, &sensor->ep);
369519a81c14SSteve Longerbeam 	fwnode_handle_put(endpoint);
369619a81c14SSteve Longerbeam 	if (ret) {
369719a81c14SSteve Longerbeam 		dev_err(dev, "Could not parse endpoint\n");
369819a81c14SSteve Longerbeam 		return ret;
369919a81c14SSteve Longerbeam 	}
370019a81c14SSteve Longerbeam 
37012c61e48dSLad Prabhakar 	if (sensor->ep.bus_type != V4L2_MBUS_PARALLEL &&
37022c61e48dSLad Prabhakar 	    sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY &&
37032c61e48dSLad Prabhakar 	    sensor->ep.bus_type != V4L2_MBUS_BT656) {
37042c61e48dSLad Prabhakar 		dev_err(dev, "Unsupported bus type %d\n", sensor->ep.bus_type);
37052c61e48dSLad Prabhakar 		return -EINVAL;
37062c61e48dSLad Prabhakar 	}
37072c61e48dSLad Prabhakar 
370819a81c14SSteve Longerbeam 	/* get system clock (xclk) */
370919a81c14SSteve Longerbeam 	sensor->xclk = devm_clk_get(dev, "xclk");
371019a81c14SSteve Longerbeam 	if (IS_ERR(sensor->xclk)) {
371119a81c14SSteve Longerbeam 		dev_err(dev, "failed to get xclk\n");
371219a81c14SSteve Longerbeam 		return PTR_ERR(sensor->xclk);
371319a81c14SSteve Longerbeam 	}
371419a81c14SSteve Longerbeam 
371519a81c14SSteve Longerbeam 	sensor->xclk_freq = clk_get_rate(sensor->xclk);
371619a81c14SSteve Longerbeam 	if (sensor->xclk_freq < OV5640_XCLK_MIN ||
371719a81c14SSteve Longerbeam 	    sensor->xclk_freq > OV5640_XCLK_MAX) {
371819a81c14SSteve Longerbeam 		dev_err(dev, "xclk frequency out of range: %d Hz\n",
371919a81c14SSteve Longerbeam 			sensor->xclk_freq);
372019a81c14SSteve Longerbeam 		return -EINVAL;
372119a81c14SSteve Longerbeam 	}
372219a81c14SSteve Longerbeam 
372319a81c14SSteve Longerbeam 	/* request optional power down pin */
372419a81c14SSteve Longerbeam 	sensor->pwdn_gpio = devm_gpiod_get_optional(dev, "powerdown",
372519a81c14SSteve Longerbeam 						    GPIOD_OUT_HIGH);
37268791a102SFabio Estevam 	if (IS_ERR(sensor->pwdn_gpio))
37278791a102SFabio Estevam 		return PTR_ERR(sensor->pwdn_gpio);
37288791a102SFabio Estevam 
372919a81c14SSteve Longerbeam 	/* request optional reset pin */
373019a81c14SSteve Longerbeam 	sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset",
373119a81c14SSteve Longerbeam 						     GPIOD_OUT_HIGH);
37328791a102SFabio Estevam 	if (IS_ERR(sensor->reset_gpio))
37338791a102SFabio Estevam 		return PTR_ERR(sensor->reset_gpio);
373419a81c14SSteve Longerbeam 
373519a81c14SSteve Longerbeam 	v4l2_i2c_subdev_init(&sensor->sd, client, &ov5640_subdev_ops);
373619a81c14SSteve Longerbeam 
37372d18fbc5SAkinobu Mita 	sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
37382d18fbc5SAkinobu Mita 			    V4L2_SUBDEV_FL_HAS_EVENTS;
373919a81c14SSteve Longerbeam 	sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
374019a81c14SSteve Longerbeam 	sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
374119a81c14SSteve Longerbeam 	ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
374219a81c14SSteve Longerbeam 	if (ret)
374319a81c14SSteve Longerbeam 		return ret;
374419a81c14SSteve Longerbeam 
374519a81c14SSteve Longerbeam 	ret = ov5640_get_regulators(sensor);
374619a81c14SSteve Longerbeam 	if (ret)
374719a81c14SSteve Longerbeam 		return ret;
374819a81c14SSteve Longerbeam 
374919a81c14SSteve Longerbeam 	mutex_init(&sensor->lock);
375019a81c14SSteve Longerbeam 
37510f7acb52SHugues Fruchet 	ret = ov5640_check_chip_id(sensor);
37520f7acb52SHugues Fruchet 	if (ret)
37530f7acb52SHugues Fruchet 		goto entity_cleanup;
37540f7acb52SHugues Fruchet 
375519a81c14SSteve Longerbeam 	ret = ov5640_init_controls(sensor);
375619a81c14SSteve Longerbeam 	if (ret)
375719a81c14SSteve Longerbeam 		goto entity_cleanup;
375819a81c14SSteve Longerbeam 
375915786f7bSSakari Ailus 	ret = v4l2_async_register_subdev_sensor(&sensor->sd);
376019a81c14SSteve Longerbeam 	if (ret)
376119a81c14SSteve Longerbeam 		goto free_ctrls;
376219a81c14SSteve Longerbeam 
376319a81c14SSteve Longerbeam 	return 0;
376419a81c14SSteve Longerbeam 
376519a81c14SSteve Longerbeam free_ctrls:
376619a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
376719a81c14SSteve Longerbeam entity_cleanup:
376819a81c14SSteve Longerbeam 	media_entity_cleanup(&sensor->sd.entity);
3769bfcba38dSTomi Valkeinen 	mutex_destroy(&sensor->lock);
377019a81c14SSteve Longerbeam 	return ret;
377119a81c14SSteve Longerbeam }
377219a81c14SSteve Longerbeam 
377319a81c14SSteve Longerbeam static int ov5640_remove(struct i2c_client *client)
377419a81c14SSteve Longerbeam {
377519a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
377619a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
377719a81c14SSteve Longerbeam 
377819a81c14SSteve Longerbeam 	v4l2_async_unregister_subdev(&sensor->sd);
377919a81c14SSteve Longerbeam 	media_entity_cleanup(&sensor->sd.entity);
378019a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
3781bfcba38dSTomi Valkeinen 	mutex_destroy(&sensor->lock);
378219a81c14SSteve Longerbeam 
378319a81c14SSteve Longerbeam 	return 0;
378419a81c14SSteve Longerbeam }
378519a81c14SSteve Longerbeam 
378619a81c14SSteve Longerbeam static const struct i2c_device_id ov5640_id[] = {
378719a81c14SSteve Longerbeam 	{"ov5640", 0},
378819a81c14SSteve Longerbeam 	{},
378919a81c14SSteve Longerbeam };
379019a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(i2c, ov5640_id);
379119a81c14SSteve Longerbeam 
379219a81c14SSteve Longerbeam static const struct of_device_id ov5640_dt_ids[] = {
379319a81c14SSteve Longerbeam 	{ .compatible = "ovti,ov5640" },
379419a81c14SSteve Longerbeam 	{ /* sentinel */ }
379519a81c14SSteve Longerbeam };
379619a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(of, ov5640_dt_ids);
379719a81c14SSteve Longerbeam 
379819a81c14SSteve Longerbeam static struct i2c_driver ov5640_i2c_driver = {
379919a81c14SSteve Longerbeam 	.driver = {
380019a81c14SSteve Longerbeam 		.name  = "ov5640",
380119a81c14SSteve Longerbeam 		.of_match_table	= ov5640_dt_ids,
380219a81c14SSteve Longerbeam 	},
380319a81c14SSteve Longerbeam 	.id_table = ov5640_id,
3804e6714993SKieran Bingham 	.probe_new = ov5640_probe,
380519a81c14SSteve Longerbeam 	.remove   = ov5640_remove,
380619a81c14SSteve Longerbeam };
380719a81c14SSteve Longerbeam 
380819a81c14SSteve Longerbeam module_i2c_driver(ov5640_i2c_driver);
380919a81c14SSteve Longerbeam 
381019a81c14SSteve Longerbeam MODULE_DESCRIPTION("OV5640 MIPI Camera Subdev Driver");
381119a81c14SSteve Longerbeam MODULE_LICENSE("GPL");
3812