xref: /openbmc/linux/drivers/media/i2c/ov5640.c (revision bce93b82)
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 
39*bce93b82SJacopo Mondi /* FIXME: not documented. */
40*bce93b82SJacopo Mondi #define OV5640_MIN_VBLANK	24
41*bce93b82SJacopo Mondi #define OV5640_MAX_VTS		3375
42*bce93b82SJacopo 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;
32219a81c14SSteve Longerbeam };
32319a81c14SSteve Longerbeam 
32419a81c14SSteve Longerbeam struct ov5640_ctrls {
32519a81c14SSteve Longerbeam 	struct v4l2_ctrl_handler handler;
326cc196e48SBenoit Parrot 	struct v4l2_ctrl *pixel_rate;
3277a3b8d4bSJacopo Mondi 	struct v4l2_ctrl *link_freq;
32832979f67SJacopo Mondi 	struct v4l2_ctrl *hblank;
329*bce93b82SJacopo Mondi 	struct v4l2_ctrl *vblank;
33019a81c14SSteve Longerbeam 	struct {
33119a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_exp;
33219a81c14SSteve Longerbeam 		struct v4l2_ctrl *exposure;
33319a81c14SSteve Longerbeam 	};
33419a81c14SSteve Longerbeam 	struct {
33519a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_wb;
33619a81c14SSteve Longerbeam 		struct v4l2_ctrl *blue_balance;
33719a81c14SSteve Longerbeam 		struct v4l2_ctrl *red_balance;
33819a81c14SSteve Longerbeam 	};
33919a81c14SSteve Longerbeam 	struct {
34019a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_gain;
34119a81c14SSteve Longerbeam 		struct v4l2_ctrl *gain;
34219a81c14SSteve Longerbeam 	};
34319a81c14SSteve Longerbeam 	struct v4l2_ctrl *brightness;
3441068fecaSMylène Josserand 	struct v4l2_ctrl *light_freq;
34519a81c14SSteve Longerbeam 	struct v4l2_ctrl *saturation;
34619a81c14SSteve Longerbeam 	struct v4l2_ctrl *contrast;
34719a81c14SSteve Longerbeam 	struct v4l2_ctrl *hue;
34819a81c14SSteve Longerbeam 	struct v4l2_ctrl *test_pattern;
349ce85705aSHugues Fruchet 	struct v4l2_ctrl *hflip;
350ce85705aSHugues Fruchet 	struct v4l2_ctrl *vflip;
35119a81c14SSteve Longerbeam };
35219a81c14SSteve Longerbeam 
35319a81c14SSteve Longerbeam struct ov5640_dev {
35419a81c14SSteve Longerbeam 	struct i2c_client *i2c_client;
35519a81c14SSteve Longerbeam 	struct v4l2_subdev sd;
35619a81c14SSteve Longerbeam 	struct media_pad pad;
35719a81c14SSteve Longerbeam 	struct v4l2_fwnode_endpoint ep; /* the parsed DT endpoint info */
35819a81c14SSteve Longerbeam 	struct clk *xclk; /* system clock to OV5640 */
35919a81c14SSteve Longerbeam 	u32 xclk_freq;
36019a81c14SSteve Longerbeam 
36119a81c14SSteve Longerbeam 	struct regulator_bulk_data supplies[OV5640_NUM_SUPPLIES];
36219a81c14SSteve Longerbeam 	struct gpio_desc *reset_gpio;
36319a81c14SSteve Longerbeam 	struct gpio_desc *pwdn_gpio;
364c3f3ba3eSHugues Fruchet 	bool   upside_down;
36519a81c14SSteve Longerbeam 
36619a81c14SSteve Longerbeam 	/* lock to protect all members below */
36719a81c14SSteve Longerbeam 	struct mutex lock;
36819a81c14SSteve Longerbeam 
36919a81c14SSteve Longerbeam 	int power_count;
37019a81c14SSteve Longerbeam 
37119a81c14SSteve Longerbeam 	struct v4l2_mbus_framefmt fmt;
372fb98e29fSHugues Fruchet 	bool pending_fmt_change;
37319a81c14SSteve Longerbeam 
37419a81c14SSteve Longerbeam 	const struct ov5640_mode_info *current_mode;
375985cdcb0SHugues Fruchet 	const struct ov5640_mode_info *last_mode;
37619a81c14SSteve Longerbeam 	enum ov5640_frame_rate current_fr;
37719a81c14SSteve Longerbeam 	struct v4l2_fract frame_interval;
3783c28588fSJacopo Mondi 	s64 current_link_freq;
37919a81c14SSteve Longerbeam 
38019a81c14SSteve Longerbeam 	struct ov5640_ctrls ctrls;
38119a81c14SSteve Longerbeam 
38219a81c14SSteve Longerbeam 	u32 prev_sysclk, prev_hts;
38319a81c14SSteve Longerbeam 	u32 ae_low, ae_high, ae_target;
38419a81c14SSteve Longerbeam 
38519a81c14SSteve Longerbeam 	bool pending_mode_change;
38619a81c14SSteve Longerbeam 	bool streaming;
38719a81c14SSteve Longerbeam };
38819a81c14SSteve Longerbeam 
38919a81c14SSteve Longerbeam static inline struct ov5640_dev *to_ov5640_dev(struct v4l2_subdev *sd)
39019a81c14SSteve Longerbeam {
39119a81c14SSteve Longerbeam 	return container_of(sd, struct ov5640_dev, sd);
39219a81c14SSteve Longerbeam }
39319a81c14SSteve Longerbeam 
39419a81c14SSteve Longerbeam static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
39519a81c14SSteve Longerbeam {
39619a81c14SSteve Longerbeam 	return &container_of(ctrl->handler, struct ov5640_dev,
39719a81c14SSteve Longerbeam 			     ctrls.handler)->sd;
39819a81c14SSteve Longerbeam }
39919a81c14SSteve Longerbeam 
4008e823f5cSJacopo Mondi static inline bool ov5640_is_csi2(const struct ov5640_dev *sensor)
4018e823f5cSJacopo Mondi {
4028e823f5cSJacopo Mondi 	return sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY;
4038e823f5cSJacopo Mondi }
4048e823f5cSJacopo Mondi 
40519a81c14SSteve Longerbeam /*
40619a81c14SSteve Longerbeam  * FIXME: all of these register tables are likely filled with
40719a81c14SSteve Longerbeam  * entries that set the register to their power-on default values,
40819a81c14SSteve Longerbeam  * and which are otherwise not touched by this driver. Those entries
40919a81c14SSteve Longerbeam  * should be identified and removed to speed register load time
41019a81c14SSteve Longerbeam  * over i2c.
41119a81c14SSteve Longerbeam  */
412fb98e29fSHugues Fruchet /* YUV422 UYVY VGA@30fps */
413e4359019SJacopo Mondi static const struct reg_value ov5640_init_setting[] = {
41419a81c14SSteve Longerbeam 	{0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0},
415576f5d4bSLad Prabhakar 	{0x3103, 0x03, 0, 0}, {0x3630, 0x36, 0, 0},
41619a81c14SSteve Longerbeam 	{0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0},
41719a81c14SSteve Longerbeam 	{0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0},
41819a81c14SSteve Longerbeam 	{0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0},
41919a81c14SSteve Longerbeam 	{0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, {0x3906, 0x10, 0, 0},
42019a81c14SSteve Longerbeam 	{0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, {0x3600, 0x08, 0, 0},
42119a81c14SSteve Longerbeam 	{0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, {0x3620, 0x52, 0, 0},
42219a81c14SSteve Longerbeam 	{0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, {0x3a13, 0x43, 0, 0},
42319a81c14SSteve Longerbeam 	{0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3635, 0x13, 0, 0},
42419a81c14SSteve Longerbeam 	{0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, {0x3622, 0x01, 0, 0},
42519a81c14SSteve Longerbeam 	{0x3c01, 0xa4, 0, 0}, {0x3c04, 0x28, 0, 0}, {0x3c05, 0x98, 0, 0},
42619a81c14SSteve Longerbeam 	{0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0},
42719a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
42819a81c14SSteve Longerbeam 	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
4293145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
43019a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
43119a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
43219a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
43319a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
43419a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
43519a81c14SSteve Longerbeam 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0},
43619a81c14SSteve Longerbeam 	{0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0},
437aa4bb8b8SJacopo Mondi 	{0x302e, 0x08, 0, 0}, {0x4300, 0x3f, 0, 0},
4382b5c18f9SChen-Yu Tsai 	{0x501f, 0x00, 0, 0}, {0x4407, 0x04, 0, 0},
43919a81c14SSteve Longerbeam 	{0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
440aa4bb8b8SJacopo Mondi 	{0x4837, 0x0a, 0, 0}, {0x3824, 0x02, 0, 0},
44119a81c14SSteve Longerbeam 	{0x5000, 0xa7, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0},
44219a81c14SSteve Longerbeam 	{0x5181, 0xf2, 0, 0}, {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0},
44319a81c14SSteve Longerbeam 	{0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0},
44419a81c14SSteve Longerbeam 	{0x5187, 0x09, 0, 0}, {0x5188, 0x09, 0, 0}, {0x5189, 0x88, 0, 0},
44519a81c14SSteve Longerbeam 	{0x518a, 0x54, 0, 0}, {0x518b, 0xee, 0, 0}, {0x518c, 0xb2, 0, 0},
44619a81c14SSteve Longerbeam 	{0x518d, 0x50, 0, 0}, {0x518e, 0x34, 0, 0}, {0x518f, 0x6b, 0, 0},
44719a81c14SSteve Longerbeam 	{0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0},
44819a81c14SSteve Longerbeam 	{0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0},
44919a81c14SSteve Longerbeam 	{0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0},
45019a81c14SSteve Longerbeam 	{0x5199, 0x6c, 0, 0}, {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0},
45119a81c14SSteve Longerbeam 	{0x519c, 0x09, 0, 0}, {0x519d, 0x2b, 0, 0}, {0x519e, 0x38, 0, 0},
45219a81c14SSteve Longerbeam 	{0x5381, 0x1e, 0, 0}, {0x5382, 0x5b, 0, 0}, {0x5383, 0x08, 0, 0},
45319a81c14SSteve Longerbeam 	{0x5384, 0x0a, 0, 0}, {0x5385, 0x7e, 0, 0}, {0x5386, 0x88, 0, 0},
45419a81c14SSteve Longerbeam 	{0x5387, 0x7c, 0, 0}, {0x5388, 0x6c, 0, 0}, {0x5389, 0x10, 0, 0},
45519a81c14SSteve Longerbeam 	{0x538a, 0x01, 0, 0}, {0x538b, 0x98, 0, 0}, {0x5300, 0x08, 0, 0},
45619a81c14SSteve Longerbeam 	{0x5301, 0x30, 0, 0}, {0x5302, 0x10, 0, 0}, {0x5303, 0x00, 0, 0},
45719a81c14SSteve Longerbeam 	{0x5304, 0x08, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x08, 0, 0},
45819a81c14SSteve Longerbeam 	{0x5307, 0x16, 0, 0}, {0x5309, 0x08, 0, 0}, {0x530a, 0x30, 0, 0},
45919a81c14SSteve Longerbeam 	{0x530b, 0x04, 0, 0}, {0x530c, 0x06, 0, 0}, {0x5480, 0x01, 0, 0},
46019a81c14SSteve Longerbeam 	{0x5481, 0x08, 0, 0}, {0x5482, 0x14, 0, 0}, {0x5483, 0x28, 0, 0},
46119a81c14SSteve Longerbeam 	{0x5484, 0x51, 0, 0}, {0x5485, 0x65, 0, 0}, {0x5486, 0x71, 0, 0},
46219a81c14SSteve Longerbeam 	{0x5487, 0x7d, 0, 0}, {0x5488, 0x87, 0, 0}, {0x5489, 0x91, 0, 0},
46319a81c14SSteve Longerbeam 	{0x548a, 0x9a, 0, 0}, {0x548b, 0xaa, 0, 0}, {0x548c, 0xb8, 0, 0},
46419a81c14SSteve Longerbeam 	{0x548d, 0xcd, 0, 0}, {0x548e, 0xdd, 0, 0}, {0x548f, 0xea, 0, 0},
46519a81c14SSteve Longerbeam 	{0x5490, 0x1d, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5583, 0x40, 0, 0},
46619a81c14SSteve Longerbeam 	{0x5584, 0x10, 0, 0}, {0x5589, 0x10, 0, 0}, {0x558a, 0x00, 0, 0},
46719a81c14SSteve Longerbeam 	{0x558b, 0xf8, 0, 0}, {0x5800, 0x23, 0, 0}, {0x5801, 0x14, 0, 0},
46819a81c14SSteve Longerbeam 	{0x5802, 0x0f, 0, 0}, {0x5803, 0x0f, 0, 0}, {0x5804, 0x12, 0, 0},
46919a81c14SSteve Longerbeam 	{0x5805, 0x26, 0, 0}, {0x5806, 0x0c, 0, 0}, {0x5807, 0x08, 0, 0},
47019a81c14SSteve Longerbeam 	{0x5808, 0x05, 0, 0}, {0x5809, 0x05, 0, 0}, {0x580a, 0x08, 0, 0},
47119a81c14SSteve Longerbeam 	{0x580b, 0x0d, 0, 0}, {0x580c, 0x08, 0, 0}, {0x580d, 0x03, 0, 0},
47219a81c14SSteve Longerbeam 	{0x580e, 0x00, 0, 0}, {0x580f, 0x00, 0, 0}, {0x5810, 0x03, 0, 0},
47319a81c14SSteve Longerbeam 	{0x5811, 0x09, 0, 0}, {0x5812, 0x07, 0, 0}, {0x5813, 0x03, 0, 0},
47419a81c14SSteve Longerbeam 	{0x5814, 0x00, 0, 0}, {0x5815, 0x01, 0, 0}, {0x5816, 0x03, 0, 0},
47519a81c14SSteve Longerbeam 	{0x5817, 0x08, 0, 0}, {0x5818, 0x0d, 0, 0}, {0x5819, 0x08, 0, 0},
47619a81c14SSteve Longerbeam 	{0x581a, 0x05, 0, 0}, {0x581b, 0x06, 0, 0}, {0x581c, 0x08, 0, 0},
47719a81c14SSteve Longerbeam 	{0x581d, 0x0e, 0, 0}, {0x581e, 0x29, 0, 0}, {0x581f, 0x17, 0, 0},
47819a81c14SSteve Longerbeam 	{0x5820, 0x11, 0, 0}, {0x5821, 0x11, 0, 0}, {0x5822, 0x15, 0, 0},
47919a81c14SSteve Longerbeam 	{0x5823, 0x28, 0, 0}, {0x5824, 0x46, 0, 0}, {0x5825, 0x26, 0, 0},
48019a81c14SSteve Longerbeam 	{0x5826, 0x08, 0, 0}, {0x5827, 0x26, 0, 0}, {0x5828, 0x64, 0, 0},
48119a81c14SSteve Longerbeam 	{0x5829, 0x26, 0, 0}, {0x582a, 0x24, 0, 0}, {0x582b, 0x22, 0, 0},
48219a81c14SSteve Longerbeam 	{0x582c, 0x24, 0, 0}, {0x582d, 0x24, 0, 0}, {0x582e, 0x06, 0, 0},
48319a81c14SSteve Longerbeam 	{0x582f, 0x22, 0, 0}, {0x5830, 0x40, 0, 0}, {0x5831, 0x42, 0, 0},
48419a81c14SSteve Longerbeam 	{0x5832, 0x24, 0, 0}, {0x5833, 0x26, 0, 0}, {0x5834, 0x24, 0, 0},
48519a81c14SSteve Longerbeam 	{0x5835, 0x22, 0, 0}, {0x5836, 0x22, 0, 0}, {0x5837, 0x26, 0, 0},
48619a81c14SSteve Longerbeam 	{0x5838, 0x44, 0, 0}, {0x5839, 0x24, 0, 0}, {0x583a, 0x26, 0, 0},
48719a81c14SSteve Longerbeam 	{0x583b, 0x28, 0, 0}, {0x583c, 0x42, 0, 0}, {0x583d, 0xce, 0, 0},
48819a81c14SSteve Longerbeam 	{0x5025, 0x00, 0, 0}, {0x3a0f, 0x30, 0, 0}, {0x3a10, 0x28, 0, 0},
48919a81c14SSteve Longerbeam 	{0x3a1b, 0x30, 0, 0}, {0x3a1e, 0x26, 0, 0}, {0x3a11, 0x60, 0, 0},
49019a81c14SSteve Longerbeam 	{0x3a1f, 0x14, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3c00, 0x04, 0, 300},
49119a81c14SSteve Longerbeam };
49219a81c14SSteve Longerbeam 
493db15c195SJacopo Mondi static const struct reg_value ov5640_setting_low_res[] = {
494c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
49519a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
496ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
4973145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
49819a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
49919a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
50019a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
50119a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
50219a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5032b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
504e15197bdSJacopo Mondi 	{0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0},
50519a81c14SSteve Longerbeam };
50619a81c14SSteve Longerbeam 
507086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_720P_1280_720[] = {
508c14d107eSMaxime Ripard 	{0x3c07, 0x07, 0, 0},
50919a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
510ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
5113145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
51219a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
51319a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0},
51419a81c14SSteve Longerbeam 	{0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0},
51519a81c14SSteve Longerbeam 	{0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0},
51619a81c14SSteve Longerbeam 	{0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0},
5172b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
51819a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
51919a81c14SSteve Longerbeam 	{0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0},
52019a81c14SSteve Longerbeam };
52119a81c14SSteve Longerbeam 
522086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_1080P_1920_1080[] = {
523c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
52419a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
525ce85705aSHugues Fruchet 	{0x3814, 0x11, 0, 0},
5263145efcdSJacopo Mondi 	{0x3815, 0x11, 0, 0},
52719a81c14SSteve Longerbeam 	{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
52819a81c14SSteve Longerbeam 	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
52919a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
53019a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
53119a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5322b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0},
53319a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
534c14d107eSMaxime Ripard 	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0},
535c14d107eSMaxime Ripard 	{0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0},
53619a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
537476dec01SMaxime Ripard 	{0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0},
53819a81c14SSteve Longerbeam 	{0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0},
53919a81c14SSteve Longerbeam 	{0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0},
54019a81c14SSteve Longerbeam 	{0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0},
5412b5c18f9SChen-Yu Tsai 	{0x3a15, 0x60, 0, 0}, {0x4407, 0x04, 0, 0},
54219a81c14SSteve Longerbeam 	{0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0},
54392b9096cSBenoit Parrot 	{0x4005, 0x1a, 0, 0},
54419a81c14SSteve Longerbeam };
54519a81c14SSteve Longerbeam 
546086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_QSXGA_2592_1944[] = {
547c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
54819a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
549ce85705aSHugues Fruchet 	{0x3814, 0x11, 0, 0},
5503145efcdSJacopo Mondi 	{0x3815, 0x11, 0, 0},
55119a81c14SSteve Longerbeam 	{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
55219a81c14SSteve Longerbeam 	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
55319a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
55419a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
55519a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5562b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0},
55719a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
55819a81c14SSteve Longerbeam 	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70},
55919a81c14SSteve Longerbeam };
56019a81c14SSteve Longerbeam 
5615113d5b3SJacopo Mondi static const struct ov5640_mode_info ov5640_mode_data[OV5640_NUM_MODES] = {
5628409d017SJacopo Mondi 	{
5638409d017SJacopo Mondi 		/* 160x120 */
5643145efcdSJacopo Mondi 		.id		= OV5640_MODE_QQVGA_160_120,
5653145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
5663145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
5675113d5b3SJacopo Mondi 		.width		= 160,
5685113d5b3SJacopo Mondi 		.height		= 120,
5695113d5b3SJacopo Mondi 		.dvp_timings = {
5703145efcdSJacopo Mondi 			.analog_crop = {
5713145efcdSJacopo Mondi 				.left	= 0,
5723145efcdSJacopo Mondi 				.top	= 4,
5733145efcdSJacopo Mondi 				.width	= 2624,
5743145efcdSJacopo Mondi 				.height	= 1944,
5753145efcdSJacopo Mondi 			},
5763145efcdSJacopo Mondi 			.crop = {
5773145efcdSJacopo Mondi 				.left	= 16,
5783145efcdSJacopo Mondi 				.top	= 6,
5793145efcdSJacopo Mondi 				.width	= 160,
5803145efcdSJacopo Mondi 				.height	= 120,
5813145efcdSJacopo Mondi 			},
5823145efcdSJacopo Mondi 			.htot		= 1896,
5833145efcdSJacopo Mondi 			.vblank_def	= 864,
5845113d5b3SJacopo Mondi 		},
5855113d5b3SJacopo Mondi 		.csi2_timings = {
5865113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
5875113d5b3SJacopo Mondi 			.analog_crop = {
5885113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
5895113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
5905113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
5915113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
5925113d5b3SJacopo Mondi 			},
5935113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
5945113d5b3SJacopo Mondi 			.crop = {
5955113d5b3SJacopo Mondi 				.left	= 2,
5965113d5b3SJacopo Mondi 				.top	= 4,
5975113d5b3SJacopo Mondi 				.width	= 160,
5985113d5b3SJacopo Mondi 				.height	= 120,
5995113d5b3SJacopo Mondi 			},
6005113d5b3SJacopo Mondi 			.htot		= 1896,
6015113d5b3SJacopo Mondi 			.vblank_def	= 864,
6025113d5b3SJacopo Mondi 		},
603db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
604db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
6053145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
6068409d017SJacopo Mondi 	}, {
6078409d017SJacopo Mondi 		/* 176x144 */
6083145efcdSJacopo Mondi 		.id		= OV5640_MODE_QCIF_176_144,
6093145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
6103145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
6115113d5b3SJacopo Mondi 		.width		= 176,
6125113d5b3SJacopo Mondi 		.height		= 144,
6135113d5b3SJacopo Mondi 		.dvp_timings = {
6143145efcdSJacopo Mondi 			.analog_crop = {
6153145efcdSJacopo Mondi 				.left	= 0,
6163145efcdSJacopo Mondi 				.top	= 4,
6173145efcdSJacopo Mondi 				.width	= 2624,
6183145efcdSJacopo Mondi 				.height	= 1944,
6193145efcdSJacopo Mondi 			},
6203145efcdSJacopo Mondi 			.crop = {
6213145efcdSJacopo Mondi 				.left	= 16,
6223145efcdSJacopo Mondi 				.top	= 6,
6233145efcdSJacopo Mondi 				.width	= 176,
6243145efcdSJacopo Mondi 				.height	= 144,
6253145efcdSJacopo Mondi 			},
6263145efcdSJacopo Mondi 			.htot		= 1896,
6273145efcdSJacopo Mondi 			.vblank_def	= 840,
6285113d5b3SJacopo Mondi 		},
6295113d5b3SJacopo Mondi 		.csi2_timings = {
6305113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
6315113d5b3SJacopo Mondi 			.analog_crop = {
6325113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
6335113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
6345113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
6355113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
6365113d5b3SJacopo Mondi 			},
6375113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
6385113d5b3SJacopo Mondi 			.crop = {
6395113d5b3SJacopo Mondi 				.left	= 2,
6405113d5b3SJacopo Mondi 				.top	= 4,
6415113d5b3SJacopo Mondi 				.width	= 176,
6425113d5b3SJacopo Mondi 				.height	= 144,
6435113d5b3SJacopo Mondi 			},
6445113d5b3SJacopo Mondi 			.htot		= 1896,
6455113d5b3SJacopo Mondi 			.vblank_def	= 840,
6465113d5b3SJacopo Mondi 		},
647db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
648db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
6493145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
6508409d017SJacopo Mondi 	}, {
6518409d017SJacopo Mondi 		/* 320x240 */
6523145efcdSJacopo Mondi 		.id		= OV5640_MODE_QVGA_320_240,
6533145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
6545113d5b3SJacopo Mondi 		.width		= 320,
6555113d5b3SJacopo Mondi 		.height		= 240,
6563145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
6575113d5b3SJacopo Mondi 		.dvp_timings = {
6583145efcdSJacopo Mondi 			.analog_crop = {
6593145efcdSJacopo Mondi 				.left	= 0,
6603145efcdSJacopo Mondi 				.top	= 4,
6613145efcdSJacopo Mondi 				.width	= 2624,
6623145efcdSJacopo Mondi 				.height	= 1944,
6633145efcdSJacopo Mondi 			},
6643145efcdSJacopo Mondi 			.crop = {
6653145efcdSJacopo Mondi 				.left	= 16,
6663145efcdSJacopo Mondi 				.top	= 6,
6673145efcdSJacopo Mondi 				.width	= 320,
6683145efcdSJacopo Mondi 				.height	= 240,
6693145efcdSJacopo Mondi 			},
6703145efcdSJacopo Mondi 			.htot		= 1896,
6713145efcdSJacopo Mondi 			.vblank_def	= 744,
6725113d5b3SJacopo Mondi 		},
6735113d5b3SJacopo Mondi 		.csi2_timings = {
6745113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
6755113d5b3SJacopo Mondi 			.analog_crop = {
6765113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
6775113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
6785113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
6795113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
6805113d5b3SJacopo Mondi 			},
6815113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
6825113d5b3SJacopo Mondi 			.crop = {
6835113d5b3SJacopo Mondi 				.left	= 2,
6845113d5b3SJacopo Mondi 				.top	= 4,
6855113d5b3SJacopo Mondi 				.width	= 320,
6865113d5b3SJacopo Mondi 				.height	= 240,
6875113d5b3SJacopo Mondi 			},
6885113d5b3SJacopo Mondi 			.htot		= 1896,
6895113d5b3SJacopo Mondi 			.vblank_def	= 744,
6905113d5b3SJacopo Mondi 		},
691db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
692db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
6933145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
6948409d017SJacopo Mondi 	}, {
6958409d017SJacopo Mondi 		/* 640x480 */
6963145efcdSJacopo Mondi 		.id		= OV5640_MODE_VGA_640_480,
6973145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
6983145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
6995113d5b3SJacopo Mondi 		.width		= 640,
7005113d5b3SJacopo Mondi 		.height		= 480,
7015113d5b3SJacopo Mondi 		.dvp_timings = {
7023145efcdSJacopo Mondi 			.analog_crop = {
7033145efcdSJacopo Mondi 				.left	= 0,
7043145efcdSJacopo Mondi 				.top	= 4,
7053145efcdSJacopo Mondi 				.width	= 2624,
7063145efcdSJacopo Mondi 				.height	= 1944,
7073145efcdSJacopo Mondi 			},
7083145efcdSJacopo Mondi 			.crop = {
7093145efcdSJacopo Mondi 				.left	= 16,
7103145efcdSJacopo Mondi 				.top	= 6,
7113145efcdSJacopo Mondi 				.width	= 640,
7123145efcdSJacopo Mondi 				.height	= 480,
7133145efcdSJacopo Mondi 			},
7143145efcdSJacopo Mondi 			.htot		= 1896,
7153145efcdSJacopo Mondi 			.vblank_def	= 600,
7165113d5b3SJacopo Mondi 		},
7175113d5b3SJacopo Mondi 		.csi2_timings = {
7185113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
7195113d5b3SJacopo Mondi 			.analog_crop = {
7205113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
7215113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
7225113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
7235113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
7245113d5b3SJacopo Mondi 			},
7255113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
7265113d5b3SJacopo Mondi 			.crop = {
7275113d5b3SJacopo Mondi 				.left	= 2,
7285113d5b3SJacopo Mondi 				.top	= 4,
7295113d5b3SJacopo Mondi 				.width	= 640,
7305113d5b3SJacopo Mondi 				.height	= 480,
7315113d5b3SJacopo Mondi 			},
7325113d5b3SJacopo Mondi 			.htot		= 1896,
7335113d5b3SJacopo Mondi 			.vblank_def	= 600,
7345113d5b3SJacopo Mondi 		},
735db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
736db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
7373145efcdSJacopo Mondi 		.max_fps	= OV5640_60_FPS
7388409d017SJacopo Mondi 	}, {
7398409d017SJacopo Mondi 		/* 720x480 */
7403145efcdSJacopo Mondi 		.id		= OV5640_MODE_NTSC_720_480,
7413145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
7425113d5b3SJacopo Mondi 		.width		= 720,
7435113d5b3SJacopo Mondi 		.height		= 480,
7443145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
7455113d5b3SJacopo Mondi 		.dvp_timings = {
7463145efcdSJacopo Mondi 			.analog_crop = {
7473145efcdSJacopo Mondi 				.left	= 0,
7483145efcdSJacopo Mondi 				.top	= 4,
7493145efcdSJacopo Mondi 				.width	= 2624,
7503145efcdSJacopo Mondi 				.height	= 1944,
7513145efcdSJacopo Mondi 			},
7523145efcdSJacopo Mondi 			.crop = {
753e74ef55bSJacopo Mondi 				.left	= 56,
7543145efcdSJacopo Mondi 				.top	= 60,
7553145efcdSJacopo Mondi 				.width	= 720,
7563145efcdSJacopo Mondi 				.height	= 480,
7573145efcdSJacopo Mondi 			},
7583145efcdSJacopo Mondi 			.htot		= 1896,
7593145efcdSJacopo Mondi 			.vblank_def	= 504,
7605113d5b3SJacopo Mondi 		},
7615113d5b3SJacopo Mondi 		.csi2_timings = {
7625113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
7635113d5b3SJacopo Mondi 			.analog_crop = {
7645113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
7655113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
7665113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
7675113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
7685113d5b3SJacopo Mondi 			},
7695113d5b3SJacopo Mondi 			.crop = {
7705113d5b3SJacopo Mondi 				.left	= 56,
7715113d5b3SJacopo Mondi 				.top	= 60,
7725113d5b3SJacopo Mondi 				.width	= 720,
7735113d5b3SJacopo Mondi 				.height	= 480,
7745113d5b3SJacopo Mondi 			},
7755113d5b3SJacopo Mondi 			.htot		= 1896,
7765113d5b3SJacopo Mondi 			.vblank_def	= 504,
7775113d5b3SJacopo Mondi 		},
778db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
779db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
7803145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
7818409d017SJacopo Mondi 	}, {
7828409d017SJacopo Mondi 		/* 720x576 */
7833145efcdSJacopo Mondi 		.id		= OV5640_MODE_PAL_720_576,
7843145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
7855113d5b3SJacopo Mondi 		.width		= 720,
7865113d5b3SJacopo Mondi 		.height		= 576,
7873145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
7885113d5b3SJacopo Mondi 		.dvp_timings = {
7893145efcdSJacopo Mondi 			.analog_crop = {
7903145efcdSJacopo Mondi 				.left	= 0,
7913145efcdSJacopo Mondi 				.top	= 4,
7923145efcdSJacopo Mondi 				.width	= 2624,
7933145efcdSJacopo Mondi 				.height	= 1944,
7943145efcdSJacopo Mondi 			},
7953145efcdSJacopo Mondi 			.crop = {
7963145efcdSJacopo Mondi 				.left	= 56,
7973145efcdSJacopo Mondi 				.top	= 6,
7983145efcdSJacopo Mondi 				.width	= 720,
7993145efcdSJacopo Mondi 				.height	= 576,
8003145efcdSJacopo Mondi 			},
8013145efcdSJacopo Mondi 			.htot		= 1896,
8023145efcdSJacopo Mondi 			.vblank_def	= 408,
8035113d5b3SJacopo Mondi 		},
8045113d5b3SJacopo Mondi 		.csi2_timings = {
8055113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
8065113d5b3SJacopo Mondi 			.analog_crop = {
8075113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
8085113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
8095113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
8105113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
8115113d5b3SJacopo Mondi 			},
8125113d5b3SJacopo Mondi 			.crop = {
8135113d5b3SJacopo Mondi 				.left	= 56,
8145113d5b3SJacopo Mondi 				.top	= 6,
8155113d5b3SJacopo Mondi 				.width	= 720,
8165113d5b3SJacopo Mondi 				.height	= 576,
8175113d5b3SJacopo Mondi 			},
8185113d5b3SJacopo Mondi 			.htot		= 1896,
8195113d5b3SJacopo Mondi 			.vblank_def	= 408,
8205113d5b3SJacopo Mondi 		},
821db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
822db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
8233145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
8248409d017SJacopo Mondi 	}, {
8258409d017SJacopo Mondi 		/* 1024x768 */
8263145efcdSJacopo Mondi 		.id		= OV5640_MODE_XGA_1024_768,
8273145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
8283145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
8295113d5b3SJacopo Mondi 		.width		= 1024,
8305113d5b3SJacopo Mondi 		.height		= 768,
8315113d5b3SJacopo Mondi 		.dvp_timings = {
8323145efcdSJacopo Mondi 			.analog_crop = {
8333145efcdSJacopo Mondi 				.left	= 0,
8343145efcdSJacopo Mondi 				.top	= 4,
8353145efcdSJacopo Mondi 				.width	= 2624,
8363145efcdSJacopo Mondi 				.height	= 1944,
8373145efcdSJacopo Mondi 			},
8383145efcdSJacopo Mondi 			.crop = {
8393145efcdSJacopo Mondi 				.left	= 16,
8403145efcdSJacopo Mondi 				.top	= 6,
8413145efcdSJacopo Mondi 				.width	= 1024,
8423145efcdSJacopo Mondi 				.height	= 768,
8433145efcdSJacopo Mondi 			},
8443145efcdSJacopo Mondi 			.htot		= 1896,
8453145efcdSJacopo Mondi 			.vblank_def	= 312,
8465113d5b3SJacopo Mondi 		},
8475113d5b3SJacopo Mondi 		.csi2_timings = {
8485113d5b3SJacopo Mondi 			.analog_crop = {
8495113d5b3SJacopo Mondi 				.left	= 0,
8505113d5b3SJacopo Mondi 				.top	= 4,
8515113d5b3SJacopo Mondi 				.width	= OV5640_NATIVE_WIDTH,
8525113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
8535113d5b3SJacopo Mondi 			},
8545113d5b3SJacopo Mondi 			.crop = {
8555113d5b3SJacopo Mondi 				.left	= 16,
8565113d5b3SJacopo Mondi 				.top	= 6,
8575113d5b3SJacopo Mondi 				.width	= 1024,
8585113d5b3SJacopo Mondi 				.height	= 768,
8595113d5b3SJacopo Mondi 			},
8605113d5b3SJacopo Mondi 			.htot		= 1896,
8615113d5b3SJacopo Mondi 			.vblank_def	= 312,
8625113d5b3SJacopo Mondi 		},
863db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
864db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
8653145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
8668409d017SJacopo Mondi 	}, {
8678409d017SJacopo Mondi 		/* 1280x720 */
8683145efcdSJacopo Mondi 		.id		= OV5640_MODE_720P_1280_720,
8693145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
8703145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_124M,
8715113d5b3SJacopo Mondi 		.width		= 1280,
8725113d5b3SJacopo Mondi 		.height		= 720,
8735113d5b3SJacopo Mondi 		.dvp_timings = {
8743145efcdSJacopo Mondi 			.analog_crop = {
8753145efcdSJacopo Mondi 				.left	= 0,
8763145efcdSJacopo Mondi 				.top	= 250,
8773145efcdSJacopo Mondi 				.width	= 2624,
8783145efcdSJacopo Mondi 				.height	= 1456,
8793145efcdSJacopo Mondi 			},
8803145efcdSJacopo Mondi 			.crop = {
8813145efcdSJacopo Mondi 				.left	= 16,
8823145efcdSJacopo Mondi 				.top	= 4,
8833145efcdSJacopo Mondi 				.width	= 1280,
8843145efcdSJacopo Mondi 				.height	= 720,
8853145efcdSJacopo Mondi 			},
8863145efcdSJacopo Mondi 			.htot		= 1892,
8873145efcdSJacopo Mondi 			.vblank_def	= 20,
8885113d5b3SJacopo Mondi 		},
8895113d5b3SJacopo Mondi 		.csi2_timings = {
8905113d5b3SJacopo Mondi 			.analog_crop = {
8915113d5b3SJacopo Mondi 				.left	= 0,
8925113d5b3SJacopo Mondi 				.top	= 250,
8935113d5b3SJacopo Mondi 				.width	= 2624,
8945113d5b3SJacopo Mondi 				.height	= 1456,
8955113d5b3SJacopo Mondi 			},
8965113d5b3SJacopo Mondi 			.crop = {
8975113d5b3SJacopo Mondi 				.left	= 16,
8985113d5b3SJacopo Mondi 				.top	= 4,
8995113d5b3SJacopo Mondi 				.width	= 1280,
9005113d5b3SJacopo Mondi 				.height	= 720,
9015113d5b3SJacopo Mondi 			},
9025113d5b3SJacopo Mondi 			.htot		= 1892,
9035113d5b3SJacopo Mondi 			.vblank_def	= 20,
9045113d5b3SJacopo Mondi 		},
9053145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_720P_1280_720,
9063145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_720P_1280_720),
9073145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
9088409d017SJacopo Mondi 	}, {
9098409d017SJacopo Mondi 		/* 1920x1080 */
9103145efcdSJacopo Mondi 		.id		= OV5640_MODE_1080P_1920_1080,
9113145efcdSJacopo Mondi 		.dn_mode	= SCALING,
9123145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_148M,
9135113d5b3SJacopo Mondi 		.width		= 1920,
9145113d5b3SJacopo Mondi 		.height		= 1080,
9155113d5b3SJacopo Mondi 		.dvp_timings = {
9163145efcdSJacopo Mondi 			.analog_crop = {
9173145efcdSJacopo Mondi 				.left	= 336,
9183145efcdSJacopo Mondi 				.top	= 434,
9193145efcdSJacopo Mondi 				.width	= 1952,
9203145efcdSJacopo Mondi 				.height	= 1088,
9213145efcdSJacopo Mondi 			},
9223145efcdSJacopo Mondi 			.crop = {
9233145efcdSJacopo Mondi 				.left	= 16,
9243145efcdSJacopo Mondi 				.top	= 4,
9253145efcdSJacopo Mondi 				.width	= 1920,
9263145efcdSJacopo Mondi 				.height	= 1080,
9273145efcdSJacopo Mondi 			},
9283145efcdSJacopo Mondi 			.htot		= 2500,
9293145efcdSJacopo Mondi 			.vblank_def	= 40,
9305113d5b3SJacopo Mondi 		},
9315113d5b3SJacopo Mondi 		.csi2_timings = {
9325113d5b3SJacopo Mondi 			/* Crop the full valid pixel array in the center. */
9335113d5b3SJacopo Mondi 			.analog_crop = {
9345113d5b3SJacopo Mondi 				.left	= 336,
9355113d5b3SJacopo Mondi 				.top	= 434,
9365113d5b3SJacopo Mondi 				.width	= 1952,
9375113d5b3SJacopo Mondi 				.height	= 1088,
9385113d5b3SJacopo Mondi 			},
9395113d5b3SJacopo Mondi 			/* Maintain a larger processing margins. */
9405113d5b3SJacopo Mondi 			.crop = {
9415113d5b3SJacopo Mondi 				.left	= 16,
9425113d5b3SJacopo Mondi 				.top	= 4,
9435113d5b3SJacopo Mondi 				.width	= 1920,
9445113d5b3SJacopo Mondi 				.height	= 1080,
9455113d5b3SJacopo Mondi 			},
9465113d5b3SJacopo Mondi 			.htot		= 2500,
9475113d5b3SJacopo Mondi 			.vblank_def	= 40,
9485113d5b3SJacopo Mondi 		},
9493145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_1080P_1920_1080,
9503145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_1080P_1920_1080),
9513145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
9528409d017SJacopo Mondi 	}, {
9538409d017SJacopo Mondi 		/* 2592x1944 */
9543145efcdSJacopo Mondi 		.id		= OV5640_MODE_QSXGA_2592_1944,
9553145efcdSJacopo Mondi 		.dn_mode	= SCALING,
9563145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_168M,
9575113d5b3SJacopo Mondi 		.width		= OV5640_PIXEL_ARRAY_WIDTH,
9585113d5b3SJacopo Mondi 		.height		= OV5640_PIXEL_ARRAY_HEIGHT,
9595113d5b3SJacopo Mondi 		.dvp_timings = {
9603145efcdSJacopo Mondi 			.analog_crop = {
9613145efcdSJacopo Mondi 				.left	= 0,
9623145efcdSJacopo Mondi 				.top	= 0,
9633145efcdSJacopo Mondi 				.width	= 2624,
9643145efcdSJacopo Mondi 				.height	= 1952,
9653145efcdSJacopo Mondi 			},
9663145efcdSJacopo Mondi 			.crop = {
9673145efcdSJacopo Mondi 				.left	= 16,
9683145efcdSJacopo Mondi 				.top	= 4,
9693145efcdSJacopo Mondi 				.width	= 2592,
9703145efcdSJacopo Mondi 				.height	= 1944,
9713145efcdSJacopo Mondi 			},
9723145efcdSJacopo Mondi 			.htot		= 2844,
9733145efcdSJacopo Mondi 			.vblank_def	= 24,
9745113d5b3SJacopo Mondi 		},
9755113d5b3SJacopo Mondi 		.csi2_timings = {
9765113d5b3SJacopo Mondi 			/* Give more processing margin to full resolution. */
9775113d5b3SJacopo Mondi 			.analog_crop = {
9785113d5b3SJacopo Mondi 				.left	= 0,
9795113d5b3SJacopo Mondi 				.top	= 0,
9805113d5b3SJacopo Mondi 				.width	= OV5640_NATIVE_WIDTH,
9815113d5b3SJacopo Mondi 				.height	= 1952,
9825113d5b3SJacopo Mondi 			},
9835113d5b3SJacopo Mondi 			.crop = {
9845113d5b3SJacopo Mondi 				.left	= 16,
9855113d5b3SJacopo Mondi 				.top	= 4,
9865113d5b3SJacopo Mondi 				.width	= 2592,
9875113d5b3SJacopo Mondi 				.height	= 1944,
9885113d5b3SJacopo Mondi 			},
9895113d5b3SJacopo Mondi 			.htot		= 2844,
9905113d5b3SJacopo Mondi 			.vblank_def	= 24,
9915113d5b3SJacopo Mondi 		},
9923145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_QSXGA_2592_1944,
9933145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_QSXGA_2592_1944),
9943145efcdSJacopo Mondi 		.max_fps	= OV5640_15_FPS
9958409d017SJacopo Mondi 	},
99619a81c14SSteve Longerbeam };
99719a81c14SSteve Longerbeam 
9982de6bb97SJacopo Mondi static const struct ov5640_timings *
9992de6bb97SJacopo Mondi ov5640_timings(const struct ov5640_dev *sensor,
10002de6bb97SJacopo Mondi 	       const struct ov5640_mode_info *mode)
10012de6bb97SJacopo Mondi {
10022de6bb97SJacopo Mondi 	if (ov5640_is_csi2(sensor))
10032de6bb97SJacopo Mondi 		return &mode->csi2_timings;
10042de6bb97SJacopo Mondi 
10052de6bb97SJacopo Mondi 	return &mode->dvp_timings;
10062de6bb97SJacopo Mondi }
10072de6bb97SJacopo Mondi 
100819a81c14SSteve Longerbeam static int ov5640_init_slave_id(struct ov5640_dev *sensor)
100919a81c14SSteve Longerbeam {
101019a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
101119a81c14SSteve Longerbeam 	struct i2c_msg msg;
101219a81c14SSteve Longerbeam 	u8 buf[3];
101319a81c14SSteve Longerbeam 	int ret;
101419a81c14SSteve Longerbeam 
101519a81c14SSteve Longerbeam 	if (client->addr == OV5640_DEFAULT_SLAVE_ID)
101619a81c14SSteve Longerbeam 		return 0;
101719a81c14SSteve Longerbeam 
101819a81c14SSteve Longerbeam 	buf[0] = OV5640_REG_SLAVE_ID >> 8;
101919a81c14SSteve Longerbeam 	buf[1] = OV5640_REG_SLAVE_ID & 0xff;
102019a81c14SSteve Longerbeam 	buf[2] = client->addr << 1;
102119a81c14SSteve Longerbeam 
102219a81c14SSteve Longerbeam 	msg.addr = OV5640_DEFAULT_SLAVE_ID;
102319a81c14SSteve Longerbeam 	msg.flags = 0;
102419a81c14SSteve Longerbeam 	msg.buf = buf;
102519a81c14SSteve Longerbeam 	msg.len = sizeof(buf);
102619a81c14SSteve Longerbeam 
102719a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, &msg, 1);
102819a81c14SSteve Longerbeam 	if (ret < 0) {
102919a81c14SSteve Longerbeam 		dev_err(&client->dev, "%s: failed with %d\n", __func__, ret);
103019a81c14SSteve Longerbeam 		return ret;
103119a81c14SSteve Longerbeam 	}
103219a81c14SSteve Longerbeam 
103319a81c14SSteve Longerbeam 	return 0;
103419a81c14SSteve Longerbeam }
103519a81c14SSteve Longerbeam 
103619a81c14SSteve Longerbeam static int ov5640_write_reg(struct ov5640_dev *sensor, u16 reg, u8 val)
103719a81c14SSteve Longerbeam {
103819a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
103919a81c14SSteve Longerbeam 	struct i2c_msg msg;
104019a81c14SSteve Longerbeam 	u8 buf[3];
104119a81c14SSteve Longerbeam 	int ret;
104219a81c14SSteve Longerbeam 
104319a81c14SSteve Longerbeam 	buf[0] = reg >> 8;
104419a81c14SSteve Longerbeam 	buf[1] = reg & 0xff;
104519a81c14SSteve Longerbeam 	buf[2] = val;
104619a81c14SSteve Longerbeam 
104719a81c14SSteve Longerbeam 	msg.addr = client->addr;
104819a81c14SSteve Longerbeam 	msg.flags = client->flags;
104919a81c14SSteve Longerbeam 	msg.buf = buf;
105019a81c14SSteve Longerbeam 	msg.len = sizeof(buf);
105119a81c14SSteve Longerbeam 
105219a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, &msg, 1);
105319a81c14SSteve Longerbeam 	if (ret < 0) {
10543924c623SHugues Fruchet 		dev_err(&client->dev, "%s: error: reg=%x, val=%x\n",
105519a81c14SSteve Longerbeam 			__func__, reg, val);
105619a81c14SSteve Longerbeam 		return ret;
105719a81c14SSteve Longerbeam 	}
105819a81c14SSteve Longerbeam 
105919a81c14SSteve Longerbeam 	return 0;
106019a81c14SSteve Longerbeam }
106119a81c14SSteve Longerbeam 
106219a81c14SSteve Longerbeam static int ov5640_read_reg(struct ov5640_dev *sensor, u16 reg, u8 *val)
106319a81c14SSteve Longerbeam {
106419a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
106519a81c14SSteve Longerbeam 	struct i2c_msg msg[2];
106619a81c14SSteve Longerbeam 	u8 buf[2];
106719a81c14SSteve Longerbeam 	int ret;
106819a81c14SSteve Longerbeam 
106919a81c14SSteve Longerbeam 	buf[0] = reg >> 8;
107019a81c14SSteve Longerbeam 	buf[1] = reg & 0xff;
107119a81c14SSteve Longerbeam 
107219a81c14SSteve Longerbeam 	msg[0].addr = client->addr;
107319a81c14SSteve Longerbeam 	msg[0].flags = client->flags;
107419a81c14SSteve Longerbeam 	msg[0].buf = buf;
107519a81c14SSteve Longerbeam 	msg[0].len = sizeof(buf);
107619a81c14SSteve Longerbeam 
107719a81c14SSteve Longerbeam 	msg[1].addr = client->addr;
107819a81c14SSteve Longerbeam 	msg[1].flags = client->flags | I2C_M_RD;
107919a81c14SSteve Longerbeam 	msg[1].buf = buf;
108019a81c14SSteve Longerbeam 	msg[1].len = 1;
108119a81c14SSteve Longerbeam 
108219a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, msg, 2);
10833924c623SHugues Fruchet 	if (ret < 0) {
10843924c623SHugues Fruchet 		dev_err(&client->dev, "%s: error: reg=%x\n",
10853924c623SHugues Fruchet 			__func__, reg);
108619a81c14SSteve Longerbeam 		return ret;
10873924c623SHugues Fruchet 	}
108819a81c14SSteve Longerbeam 
108919a81c14SSteve Longerbeam 	*val = buf[0];
109019a81c14SSteve Longerbeam 	return 0;
109119a81c14SSteve Longerbeam }
109219a81c14SSteve Longerbeam 
109319a81c14SSteve Longerbeam static int ov5640_read_reg16(struct ov5640_dev *sensor, u16 reg, u16 *val)
109419a81c14SSteve Longerbeam {
109519a81c14SSteve Longerbeam 	u8 hi, lo;
109619a81c14SSteve Longerbeam 	int ret;
109719a81c14SSteve Longerbeam 
109819a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg, &hi);
109919a81c14SSteve Longerbeam 	if (ret)
110019a81c14SSteve Longerbeam 		return ret;
110119a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg + 1, &lo);
110219a81c14SSteve Longerbeam 	if (ret)
110319a81c14SSteve Longerbeam 		return ret;
110419a81c14SSteve Longerbeam 
110519a81c14SSteve Longerbeam 	*val = ((u16)hi << 8) | (u16)lo;
110619a81c14SSteve Longerbeam 	return 0;
110719a81c14SSteve Longerbeam }
110819a81c14SSteve Longerbeam 
110919a81c14SSteve Longerbeam static int ov5640_write_reg16(struct ov5640_dev *sensor, u16 reg, u16 val)
111019a81c14SSteve Longerbeam {
111119a81c14SSteve Longerbeam 	int ret;
111219a81c14SSteve Longerbeam 
111319a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, reg, val >> 8);
111419a81c14SSteve Longerbeam 	if (ret)
111519a81c14SSteve Longerbeam 		return ret;
111619a81c14SSteve Longerbeam 
111719a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, reg + 1, val & 0xff);
111819a81c14SSteve Longerbeam }
111919a81c14SSteve Longerbeam 
112019a81c14SSteve Longerbeam static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg,
112119a81c14SSteve Longerbeam 			  u8 mask, u8 val)
112219a81c14SSteve Longerbeam {
112319a81c14SSteve Longerbeam 	u8 readval;
112419a81c14SSteve Longerbeam 	int ret;
112519a81c14SSteve Longerbeam 
112619a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg, &readval);
112719a81c14SSteve Longerbeam 	if (ret)
112819a81c14SSteve Longerbeam 		return ret;
112919a81c14SSteve Longerbeam 
113019a81c14SSteve Longerbeam 	readval &= ~mask;
113119a81c14SSteve Longerbeam 	val &= mask;
113219a81c14SSteve Longerbeam 	val |= readval;
113319a81c14SSteve Longerbeam 
113419a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, reg, val);
113519a81c14SSteve Longerbeam }
113619a81c14SSteve Longerbeam 
1137aa288248SMaxime Ripard /*
1138aa288248SMaxime Ripard  * After trying the various combinations, reading various
1139f8a7647dSMauro Carvalho Chehab  * documentations spread around the net, and from the various
1140aa288248SMaxime Ripard  * feedback, the clock tree is probably as follows:
1141aa288248SMaxime Ripard  *
1142aa288248SMaxime Ripard  *   +--------------+
1143aa288248SMaxime Ripard  *   |  Ext. Clock  |
1144aa288248SMaxime Ripard  *   +-+------------+
1145aa288248SMaxime Ripard  *     |  +----------+
1146aa288248SMaxime Ripard  *     +->|   PLL1   | - reg 0x3036, for the multiplier
1147aa288248SMaxime Ripard  *        +-+--------+ - reg 0x3037, bits 0-3 for the pre-divider
1148aa288248SMaxime Ripard  *          |  +--------------+
1149aa288248SMaxime Ripard  *          +->| System Clock |  - reg 0x3035, bits 4-7
1150aa288248SMaxime Ripard  *             +-+------------+
1151aa288248SMaxime Ripard  *               |  +--------------+
1152aa288248SMaxime Ripard  *               +->| MIPI Divider | - reg 0x3035, bits 0-3
1153aa288248SMaxime Ripard  *               |  +-+------------+
1154aa288248SMaxime Ripard  *               |    +----------------> MIPI SCLK
1155aa288248SMaxime Ripard  *               |    +  +-----+
1156aa288248SMaxime Ripard  *               |    +->| / 2 |-------> MIPI BIT CLK
1157aa288248SMaxime Ripard  *               |       +-----+
1158aa288248SMaxime Ripard  *               |  +--------------+
1159aa288248SMaxime Ripard  *               +->| PLL Root Div | - reg 0x3037, bit 4
1160aa288248SMaxime Ripard  *                  +-+------------+
1161aa288248SMaxime Ripard  *                    |  +---------+
11624c85f628SPaul Kocialkowski  *                    +->| Bit Div | - reg 0x3034, bits 0-3
1163aa288248SMaxime Ripard  *                       +-+-------+
1164aa288248SMaxime Ripard  *                         |  +-------------+
1165aa288248SMaxime Ripard  *                         +->| SCLK Div    | - reg 0x3108, bits 0-1
1166aa288248SMaxime Ripard  *                         |  +-+-----------+
1167aa288248SMaxime Ripard  *                         |    +---------------> SCLK
1168aa288248SMaxime Ripard  *                         |  +-------------+
1169aa288248SMaxime Ripard  *                         +->| SCLK 2X Div | - reg 0x3108, bits 2-3
1170aa288248SMaxime Ripard  *                         |  +-+-----------+
1171aa288248SMaxime Ripard  *                         |    +---------------> SCLK 2X
1172aa288248SMaxime Ripard  *                         |  +-------------+
1173aa288248SMaxime Ripard  *                         +->| PCLK Div    | - reg 0x3108, bits 4-5
1174aa288248SMaxime Ripard  *                            ++------------+
1175aa288248SMaxime Ripard  *                             +  +-----------+
1176aa288248SMaxime Ripard  *                             +->|   P_DIV   | - reg 0x3035, bits 0-3
1177aa288248SMaxime Ripard  *                                +-----+-----+
1178aa288248SMaxime Ripard  *                                       +------------> PCLK
1179aa288248SMaxime Ripard  *
11806c957ed7SJacopo Mondi  * There seems to be also constraints:
1181aa288248SMaxime Ripard  *  - the PLL pre-divider output rate should be in the 4-27MHz range
1182aa288248SMaxime Ripard  *  - the PLL multiplier output rate should be in the 500-1000MHz range
1183aa288248SMaxime Ripard  *  - PCLK >= SCLK * 2 in YUV, >= SCLK in Raw or JPEG
1184aa288248SMaxime Ripard  */
1185aa288248SMaxime Ripard 
1186aa288248SMaxime Ripard /*
1187aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1188aa288248SMaxime Ripard  * set to 3 in the vendor kernels.
1189aa288248SMaxime Ripard  */
1190aa288248SMaxime Ripard #define OV5640_PLL_PREDIV	3
1191aa288248SMaxime Ripard 
1192aa288248SMaxime Ripard #define OV5640_PLL_MULT_MIN	4
1193aa288248SMaxime Ripard #define OV5640_PLL_MULT_MAX	252
1194aa288248SMaxime Ripard 
1195aa288248SMaxime Ripard /*
1196aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 16, but the value is
1197aa288248SMaxime Ripard  * always set to either 1 or 2 in the vendor kernels.
1198aa288248SMaxime Ripard  */
1199aa288248SMaxime Ripard #define OV5640_SYSDIV_MIN	1
1200aa288248SMaxime Ripard #define OV5640_SYSDIV_MAX	16
1201aa288248SMaxime Ripard 
1202aa288248SMaxime Ripard /*
1203aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 2, but the value is always
1204aa288248SMaxime Ripard  * set to 2 in the vendor kernels.
1205aa288248SMaxime Ripard  */
1206aa288248SMaxime Ripard #define OV5640_PLL_ROOT_DIV			2
1207aa288248SMaxime Ripard #define OV5640_PLL_CTRL3_PLL_ROOT_DIV_2		BIT(4)
1208aa288248SMaxime Ripard 
1209aa288248SMaxime Ripard /*
1210aa288248SMaxime Ripard  * We only supports 8-bit formats at the moment
1211aa288248SMaxime Ripard  */
1212aa288248SMaxime Ripard #define OV5640_BIT_DIV				2
1213aa288248SMaxime Ripard #define OV5640_PLL_CTRL0_MIPI_MODE_8BIT		0x08
1214aa288248SMaxime Ripard 
1215aa288248SMaxime Ripard /*
1216aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1217aa288248SMaxime Ripard  * set to 2 in the vendor kernels.
1218aa288248SMaxime Ripard  */
1219aa288248SMaxime Ripard #define OV5640_SCLK_ROOT_DIV	2
1220aa288248SMaxime Ripard 
1221aa288248SMaxime Ripard /*
1222aa288248SMaxime Ripard  * This is hardcoded so that the consistency is maintained between SCLK and
1223aa288248SMaxime Ripard  * SCLK 2x.
1224aa288248SMaxime Ripard  */
1225aa288248SMaxime Ripard #define OV5640_SCLK2X_ROOT_DIV (OV5640_SCLK_ROOT_DIV / 2)
1226aa288248SMaxime Ripard 
1227aa288248SMaxime Ripard /*
1228aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1229aa288248SMaxime Ripard  * set to 1 in the vendor kernels.
1230aa288248SMaxime Ripard  */
1231aa288248SMaxime Ripard #define OV5640_PCLK_ROOT_DIV			1
1232aa288248SMaxime Ripard #define OV5640_PLL_SYS_ROOT_DIVIDER_BYPASS	0x00
1233aa288248SMaxime Ripard 
1234aa288248SMaxime Ripard static unsigned long ov5640_compute_sys_clk(struct ov5640_dev *sensor,
1235aa288248SMaxime Ripard 					    u8 pll_prediv, u8 pll_mult,
1236aa288248SMaxime Ripard 					    u8 sysdiv)
1237aa288248SMaxime Ripard {
1238aa288248SMaxime Ripard 	unsigned long sysclk = sensor->xclk_freq / pll_prediv * pll_mult;
1239aa288248SMaxime Ripard 
1240aa288248SMaxime Ripard 	/* PLL1 output cannot exceed 1GHz. */
1241aa288248SMaxime Ripard 	if (sysclk / 1000000 > 1000)
1242aa288248SMaxime Ripard 		return 0;
1243aa288248SMaxime Ripard 
1244aa288248SMaxime Ripard 	return sysclk / sysdiv;
1245aa288248SMaxime Ripard }
1246aa288248SMaxime Ripard 
1247aa288248SMaxime Ripard static unsigned long ov5640_calc_sys_clk(struct ov5640_dev *sensor,
1248aa288248SMaxime Ripard 					 unsigned long rate,
1249aa288248SMaxime Ripard 					 u8 *pll_prediv, u8 *pll_mult,
1250aa288248SMaxime Ripard 					 u8 *sysdiv)
1251aa288248SMaxime Ripard {
1252aa288248SMaxime Ripard 	unsigned long best = ~0;
1253aa288248SMaxime Ripard 	u8 best_sysdiv = 1, best_mult = 1;
1254aa288248SMaxime Ripard 	u8 _sysdiv, _pll_mult;
1255aa288248SMaxime Ripard 
1256aa288248SMaxime Ripard 	for (_sysdiv = OV5640_SYSDIV_MIN;
1257aa288248SMaxime Ripard 	     _sysdiv <= OV5640_SYSDIV_MAX;
1258aa288248SMaxime Ripard 	     _sysdiv++) {
1259aa288248SMaxime Ripard 		for (_pll_mult = OV5640_PLL_MULT_MIN;
1260aa288248SMaxime Ripard 		     _pll_mult <= OV5640_PLL_MULT_MAX;
1261aa288248SMaxime Ripard 		     _pll_mult++) {
1262aa288248SMaxime Ripard 			unsigned long _rate;
1263aa288248SMaxime Ripard 
1264aa288248SMaxime Ripard 			/*
1265aa288248SMaxime Ripard 			 * The PLL multiplier cannot be odd if above
1266aa288248SMaxime Ripard 			 * 127.
1267aa288248SMaxime Ripard 			 */
1268aa288248SMaxime Ripard 			if (_pll_mult > 127 && (_pll_mult % 2))
1269aa288248SMaxime Ripard 				continue;
1270aa288248SMaxime Ripard 
1271aa288248SMaxime Ripard 			_rate = ov5640_compute_sys_clk(sensor,
1272aa288248SMaxime Ripard 						       OV5640_PLL_PREDIV,
1273aa288248SMaxime Ripard 						       _pll_mult, _sysdiv);
1274aa288248SMaxime Ripard 
1275aa288248SMaxime Ripard 			/*
1276aa288248SMaxime Ripard 			 * We have reached the maximum allowed PLL1 output,
1277aa288248SMaxime Ripard 			 * increase sysdiv.
1278aa288248SMaxime Ripard 			 */
12792e3df204SAdam Ford 			if (!_rate)
1280aa288248SMaxime Ripard 				break;
1281aa288248SMaxime Ripard 
1282aa288248SMaxime Ripard 			/*
1283aa288248SMaxime Ripard 			 * Prefer rates above the expected clock rate than
1284aa288248SMaxime Ripard 			 * below, even if that means being less precise.
1285aa288248SMaxime Ripard 			 */
1286aa288248SMaxime Ripard 			if (_rate < rate)
1287aa288248SMaxime Ripard 				continue;
1288aa288248SMaxime Ripard 
1289aa288248SMaxime Ripard 			if (abs(rate - _rate) < abs(rate - best)) {
1290aa288248SMaxime Ripard 				best = _rate;
1291aa288248SMaxime Ripard 				best_sysdiv = _sysdiv;
1292aa288248SMaxime Ripard 				best_mult = _pll_mult;
1293aa288248SMaxime Ripard 			}
1294aa288248SMaxime Ripard 
1295aa288248SMaxime Ripard 			if (_rate == rate)
1296aa288248SMaxime Ripard 				goto out;
1297aa288248SMaxime Ripard 		}
1298aa288248SMaxime Ripard 	}
1299aa288248SMaxime Ripard 
1300aa288248SMaxime Ripard out:
1301aa288248SMaxime Ripard 	*sysdiv = best_sysdiv;
1302aa288248SMaxime Ripard 	*pll_prediv = OV5640_PLL_PREDIV;
1303aa288248SMaxime Ripard 	*pll_mult = best_mult;
1304aa288248SMaxime Ripard 
1305aa288248SMaxime Ripard 	return best;
1306aa288248SMaxime Ripard }
1307aa288248SMaxime Ripard 
1308aa288248SMaxime Ripard /*
1309aa288248SMaxime Ripard  * ov5640_set_mipi_pclk() - Calculate the clock tree configuration values
1310aa288248SMaxime Ripard  *			    for the MIPI CSI-2 output.
1311aa288248SMaxime Ripard  */
13126c957ed7SJacopo Mondi static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor)
1313aa288248SMaxime Ripard {
13146c957ed7SJacopo Mondi 	u8 bit_div, mipi_div, pclk_div, sclk_div, sclk2x_div, root_div;
1315aa288248SMaxime Ripard 	u8 prediv, mult, sysdiv;
13166c957ed7SJacopo Mondi 	unsigned long link_freq;
13176c957ed7SJacopo Mondi 	unsigned long sysclk;
13186c957ed7SJacopo Mondi 	u8 pclk_period;
13196c957ed7SJacopo Mondi 	u32 sample_rate;
13206c957ed7SJacopo Mondi 	u32 num_lanes;
1321aa288248SMaxime Ripard 	int ret;
1322aa288248SMaxime Ripard 
13236c957ed7SJacopo Mondi 	/* Use the link freq computed at ov5640_update_pixel_rate() time. */
13246c957ed7SJacopo Mondi 	link_freq = sensor->current_link_freq;
13256c957ed7SJacopo Mondi 
1326aa288248SMaxime Ripard 	/*
13276c957ed7SJacopo Mondi 	 * - mipi_div - Additional divider for the MIPI lane clock.
13286c957ed7SJacopo Mondi 	 *
13296c957ed7SJacopo Mondi 	 * Higher link frequencies would make sysclk > 1GHz.
13306c957ed7SJacopo Mondi 	 * Keep the sysclk low and do not divide in the MIPI domain.
1331aa288248SMaxime Ripard 	 */
13326c957ed7SJacopo Mondi 	if (link_freq > OV5640_LINK_RATE_MAX)
13336c957ed7SJacopo Mondi 		mipi_div = 1;
1334aa288248SMaxime Ripard 	else
13356c957ed7SJacopo Mondi 		mipi_div = 2;
1336aa288248SMaxime Ripard 
13376c957ed7SJacopo Mondi 	sysclk = link_freq * mipi_div;
13386c957ed7SJacopo Mondi 	ov5640_calc_sys_clk(sensor, sysclk, &prediv, &mult, &sysdiv);
1339aa288248SMaxime Ripard 
13406c957ed7SJacopo Mondi 	/*
13416c957ed7SJacopo Mondi 	 * Adjust PLL parameters to maintain the MIPI_SCLK-to-PCLK ratio.
13426c957ed7SJacopo Mondi 	 *
13436c957ed7SJacopo Mondi 	 * - root_div = 2 (fixed)
13446c957ed7SJacopo Mondi 	 * - bit_div : MIPI 8-bit = 2; MIPI 10-bit = 2.5
13456c957ed7SJacopo Mondi 	 * - pclk_div = 1 (fixed)
13466c957ed7SJacopo Mondi 	 * - p_div  = (2 lanes ? mipi_div : 2 * mipi_div)
13476c957ed7SJacopo Mondi 	 *
13486c957ed7SJacopo Mondi 	 * This results in the following MIPI_SCLK depending on the number
13496c957ed7SJacopo Mondi 	 * of lanes:
13506c957ed7SJacopo Mondi 	 *
13516c957ed7SJacopo Mondi 	 * - 2 lanes: MIPI_SCLK = (4 or 5) * PCLK
13526c957ed7SJacopo Mondi 	 * - 1 lanes: MIPI_SCLK = (8 or 10) * PCLK
13536c957ed7SJacopo Mondi 	 */
13546c957ed7SJacopo Mondi 	root_div = OV5640_PLL_CTRL3_PLL_ROOT_DIV_2;
13556c957ed7SJacopo Mondi 	bit_div =  OV5640_PLL_CTRL0_MIPI_MODE_8BIT;
13566c957ed7SJacopo Mondi 	pclk_div = ilog2(OV5640_PCLK_ROOT_DIV);
1357aa288248SMaxime Ripard 
13586c957ed7SJacopo Mondi 	/*
13596c957ed7SJacopo Mondi 	 * Scaler clock:
13606c957ed7SJacopo Mondi 	 * - YUV: PCLK >= 2 * SCLK
13616c957ed7SJacopo Mondi 	 * - RAW or JPEG: PCLK >= SCLK
13626c957ed7SJacopo Mondi 	 * - sclk2x_div = sclk_div / 2
13636c957ed7SJacopo Mondi 	 */
13646c957ed7SJacopo Mondi 	sclk_div = ilog2(OV5640_SCLK_ROOT_DIV);
13656c957ed7SJacopo Mondi 	sclk2x_div = ilog2(OV5640_SCLK2X_ROOT_DIV);
13666c957ed7SJacopo Mondi 
13676c957ed7SJacopo Mondi 	/*
13686c957ed7SJacopo Mondi 	 * Set the pixel clock period expressed in ns with 1-bit decimal
13696c957ed7SJacopo Mondi 	 * (0x01=0.5ns).
13706c957ed7SJacopo Mondi 	 *
13716c957ed7SJacopo Mondi 	 * The register is very briefly documented. In the OV5645 datasheet it
13726c957ed7SJacopo Mondi 	 * is described as (2 * pclk period), and from testing it seems the
13736c957ed7SJacopo Mondi 	 * actual definition is 2 * 8-bit sample period.
13746c957ed7SJacopo Mondi 	 *
13756c957ed7SJacopo Mondi 	 * 2 * sample_period = (mipi_clk * 2 * num_lanes / bpp) * (bpp / 8) / 2
13766c957ed7SJacopo Mondi 	 */
13776c957ed7SJacopo Mondi 	num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes;
13786c957ed7SJacopo Mondi 	sample_rate = (link_freq * mipi_div * num_lanes * 2) / 16;
13796c957ed7SJacopo Mondi 	pclk_period = 2000000000UL / sample_rate;
13806c957ed7SJacopo Mondi 
13816c957ed7SJacopo Mondi 	/* Program the clock tree registers. */
13826c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0, 0x0f, bit_div);
13836c957ed7SJacopo Mondi 	if (ret)
13846c957ed7SJacopo Mondi 		return ret;
13856c957ed7SJacopo Mondi 
13866c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, 0xff,
13876c957ed7SJacopo Mondi 			     (sysdiv << 4) | mipi_div);
1388aa288248SMaxime Ripard 	if (ret)
1389aa288248SMaxime Ripard 		return ret;
1390aa288248SMaxime Ripard 
1391aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2, 0xff, mult);
1392aa288248SMaxime Ripard 	if (ret)
1393aa288248SMaxime Ripard 		return ret;
1394aa288248SMaxime Ripard 
13956c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3, 0x1f,
13966c957ed7SJacopo Mondi 			     root_div | prediv);
1397aa288248SMaxime Ripard 	if (ret)
1398aa288248SMaxime Ripard 		return ret;
1399aa288248SMaxime Ripard 
14006c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
14016c957ed7SJacopo Mondi 			     (pclk_div << 4) | (sclk2x_div << 2) | sclk_div);
14026c957ed7SJacopo Mondi 	if (ret)
14036c957ed7SJacopo Mondi 		return ret;
14046c957ed7SJacopo Mondi 
14056c957ed7SJacopo Mondi 	return ov5640_write_reg(sensor, OV5640_REG_PCLK_PERIOD, pclk_period);
14066c957ed7SJacopo Mondi }
14076c957ed7SJacopo Mondi 
14086c957ed7SJacopo Mondi static u32 ov5640_calc_pixel_rate(struct ov5640_dev *sensor)
14096c957ed7SJacopo Mondi {
14103145efcdSJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
14115113d5b3SJacopo Mondi 	const struct ov5640_timings *timings = &mode->dvp_timings;
14126c957ed7SJacopo Mondi 	u32 rate;
14136c957ed7SJacopo Mondi 
14145113d5b3SJacopo Mondi 	rate = timings->htot * (timings->crop.height + timings->vblank_def);
14156c957ed7SJacopo Mondi 	rate *= ov5640_framerates[sensor->current_fr];
14166c957ed7SJacopo Mondi 
14176c957ed7SJacopo Mondi 	return rate;
1418aa288248SMaxime Ripard }
1419aa288248SMaxime Ripard 
1420aa288248SMaxime Ripard static unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor,
1421aa288248SMaxime Ripard 				      unsigned long rate,
1422aa288248SMaxime Ripard 				      u8 *pll_prediv, u8 *pll_mult, u8 *sysdiv,
1423aa288248SMaxime Ripard 				      u8 *pll_rdiv, u8 *bit_div, u8 *pclk_div)
1424aa288248SMaxime Ripard {
1425aa288248SMaxime Ripard 	unsigned long _rate = rate * OV5640_PLL_ROOT_DIV * OV5640_BIT_DIV *
1426aa288248SMaxime Ripard 				OV5640_PCLK_ROOT_DIV;
1427aa288248SMaxime Ripard 
1428aa288248SMaxime Ripard 	_rate = ov5640_calc_sys_clk(sensor, _rate, pll_prediv, pll_mult,
1429aa288248SMaxime Ripard 				    sysdiv);
1430aa288248SMaxime Ripard 	*pll_rdiv = OV5640_PLL_ROOT_DIV;
1431aa288248SMaxime Ripard 	*bit_div = OV5640_BIT_DIV;
1432aa288248SMaxime Ripard 	*pclk_div = OV5640_PCLK_ROOT_DIV;
1433aa288248SMaxime Ripard 
1434aa288248SMaxime Ripard 	return _rate / *pll_rdiv / *bit_div / *pclk_div;
1435aa288248SMaxime Ripard }
1436aa288248SMaxime Ripard 
14376c957ed7SJacopo Mondi static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor)
1438aa288248SMaxime Ripard {
1439aa288248SMaxime Ripard 	u8 prediv, mult, sysdiv, pll_rdiv, bit_div, pclk_div;
14406c957ed7SJacopo Mondi 	u32 rate;
1441aa288248SMaxime Ripard 	int ret;
1442aa288248SMaxime Ripard 
14436c957ed7SJacopo Mondi 	rate = ov5640_calc_pixel_rate(sensor);
14446c957ed7SJacopo Mondi 	rate *= ov5640_code_to_bpp(sensor->fmt.code);
14456c957ed7SJacopo Mondi 	rate /= sensor->ep.bus.parallel.bus_width;
14466c957ed7SJacopo Mondi 
1447aa288248SMaxime Ripard 	ov5640_calc_pclk(sensor, rate, &prediv, &mult, &sysdiv, &pll_rdiv,
1448aa288248SMaxime Ripard 			 &bit_div, &pclk_div);
1449aa288248SMaxime Ripard 
1450aa288248SMaxime Ripard 	if (bit_div == 2)
1451aa288248SMaxime Ripard 		bit_div = 8;
1452aa288248SMaxime Ripard 
1453aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0,
1454aa288248SMaxime Ripard 			     0x0f, bit_div);
1455aa288248SMaxime Ripard 	if (ret)
1456aa288248SMaxime Ripard 		return ret;
1457aa288248SMaxime Ripard 
1458aa288248SMaxime Ripard 	/*
1459aa288248SMaxime Ripard 	 * We need to set sysdiv according to the clock, and to clear
1460aa288248SMaxime Ripard 	 * the MIPI divider.
1461aa288248SMaxime Ripard 	 */
1462aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1,
1463aa288248SMaxime Ripard 			     0xff, sysdiv << 4);
1464aa288248SMaxime Ripard 	if (ret)
1465aa288248SMaxime Ripard 		return ret;
1466aa288248SMaxime Ripard 
1467aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2,
1468aa288248SMaxime Ripard 			     0xff, mult);
1469aa288248SMaxime Ripard 	if (ret)
1470aa288248SMaxime Ripard 		return ret;
1471aa288248SMaxime Ripard 
1472aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3,
1473aa288248SMaxime Ripard 			     0x1f, prediv | ((pll_rdiv - 1) << 4));
1474aa288248SMaxime Ripard 	if (ret)
1475aa288248SMaxime Ripard 		return ret;
1476aa288248SMaxime Ripard 
1477aa288248SMaxime Ripard 	return ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x30,
1478aa288248SMaxime Ripard 			      (ilog2(pclk_div) << 4));
1479aa288248SMaxime Ripard }
1480aa288248SMaxime Ripard 
14817cb013b1SChen-Yu Tsai /* set JPEG framing sizes */
14827cb013b1SChen-Yu Tsai static int ov5640_set_jpeg_timings(struct ov5640_dev *sensor,
14837cb013b1SChen-Yu Tsai 				   const struct ov5640_mode_info *mode)
14847cb013b1SChen-Yu Tsai {
14857cb013b1SChen-Yu Tsai 	int ret;
14867cb013b1SChen-Yu Tsai 
14872b5c18f9SChen-Yu Tsai 	/*
14882b5c18f9SChen-Yu Tsai 	 * compression mode 3 timing
14892b5c18f9SChen-Yu Tsai 	 *
14902b5c18f9SChen-Yu Tsai 	 * Data is transmitted with programmable width (VFIFO_HSIZE).
14912b5c18f9SChen-Yu Tsai 	 * No padding done. Last line may have less data. Varying
14922b5c18f9SChen-Yu Tsai 	 * number of lines per frame, depending on amount of data.
14932b5c18f9SChen-Yu Tsai 	 */
14942b5c18f9SChen-Yu Tsai 	ret = ov5640_mod_reg(sensor, OV5640_REG_JPG_MODE_SELECT, 0x7, 0x3);
14952b5c18f9SChen-Yu Tsai 	if (ret < 0)
14962b5c18f9SChen-Yu Tsai 		return ret;
14972b5c18f9SChen-Yu Tsai 
14985113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_VFIFO_HSIZE, mode->width);
14997cb013b1SChen-Yu Tsai 	if (ret < 0)
15007cb013b1SChen-Yu Tsai 		return ret;
15017cb013b1SChen-Yu Tsai 
15025113d5b3SJacopo Mondi 	return ov5640_write_reg16(sensor, OV5640_REG_VFIFO_VSIZE, mode->height);
15037cb013b1SChen-Yu Tsai }
15047cb013b1SChen-Yu Tsai 
150519a81c14SSteve Longerbeam /* download ov5640 settings to sensor through i2c */
1506bad1774eSJacopo Mondi static int ov5640_set_timings(struct ov5640_dev *sensor,
1507bad1774eSJacopo Mondi 			      const struct ov5640_mode_info *mode)
1508bad1774eSJacopo Mondi {
15095113d5b3SJacopo Mondi 	const struct ov5640_timings *timings;
15105113d5b3SJacopo Mondi 	const struct v4l2_rect *analog_crop;
15115113d5b3SJacopo Mondi 	const struct v4l2_rect *crop;
1512bad1774eSJacopo Mondi 	int ret;
1513bad1774eSJacopo Mondi 
15147cb013b1SChen-Yu Tsai 	if (sensor->fmt.code == MEDIA_BUS_FMT_JPEG_1X8) {
15157cb013b1SChen-Yu Tsai 		ret = ov5640_set_jpeg_timings(sensor, mode);
15167cb013b1SChen-Yu Tsai 		if (ret < 0)
15177cb013b1SChen-Yu Tsai 			return ret;
15187cb013b1SChen-Yu Tsai 	}
15197cb013b1SChen-Yu Tsai 
15202de6bb97SJacopo Mondi 	timings = ov5640_timings(sensor, mode);
15215113d5b3SJacopo Mondi 	analog_crop = &timings->analog_crop;
15225113d5b3SJacopo Mondi 	crop = &timings->crop;
15235113d5b3SJacopo Mondi 
15243145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HS,
15253145efcdSJacopo Mondi 				 analog_crop->left);
1526bad1774eSJacopo Mondi 	if (ret < 0)
1527bad1774eSJacopo Mondi 		return ret;
1528bad1774eSJacopo Mondi 
15293145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VS,
15303145efcdSJacopo Mondi 				 analog_crop->top);
15313145efcdSJacopo Mondi 	if (ret < 0)
15323145efcdSJacopo Mondi 		return ret;
15333145efcdSJacopo Mondi 
15343145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HW,
15353145efcdSJacopo Mondi 				 analog_crop->left + analog_crop->width - 1);
15363145efcdSJacopo Mondi 	if (ret < 0)
15373145efcdSJacopo Mondi 		return ret;
15383145efcdSJacopo Mondi 
15393145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VH,
15403145efcdSJacopo Mondi 				 analog_crop->top + analog_crop->height - 1);
15413145efcdSJacopo Mondi 	if (ret < 0)
15423145efcdSJacopo Mondi 		return ret;
15433145efcdSJacopo Mondi 
15443145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HOFFS, crop->left);
15453145efcdSJacopo Mondi 	if (ret < 0)
15463145efcdSJacopo Mondi 		return ret;
15473145efcdSJacopo Mondi 
15483145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VOFFS, crop->top);
15493145efcdSJacopo Mondi 	if (ret < 0)
15503145efcdSJacopo Mondi 		return ret;
15513145efcdSJacopo Mondi 
15525113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->width);
15533145efcdSJacopo Mondi 	if (ret < 0)
15543145efcdSJacopo Mondi 		return ret;
15553145efcdSJacopo Mondi 
15565113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, mode->height);
1557bad1774eSJacopo Mondi 	if (ret < 0)
1558bad1774eSJacopo Mondi 		return ret;
1559bad1774eSJacopo Mondi 
15605113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, timings->htot);
1561bad1774eSJacopo Mondi 	if (ret < 0)
1562bad1774eSJacopo Mondi 		return ret;
1563bad1774eSJacopo Mondi 
15643145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS,
15655113d5b3SJacopo Mondi 				 mode->height + timings->vblank_def);
15663145efcdSJacopo Mondi 	if (ret < 0)
15673145efcdSJacopo Mondi 		return ret;
15683145efcdSJacopo Mondi 
15693145efcdSJacopo Mondi 	return 0;
1570bad1774eSJacopo Mondi }
1571bad1774eSJacopo Mondi 
1572e4359019SJacopo Mondi static void ov5640_load_regs(struct ov5640_dev *sensor,
1573e4359019SJacopo Mondi 			     const struct reg_value *regs, unsigned int regnum)
157419a81c14SSteve Longerbeam {
157519a81c14SSteve Longerbeam 	unsigned int i;
157619a81c14SSteve Longerbeam 	u32 delay_ms;
157719a81c14SSteve Longerbeam 	u16 reg_addr;
157819a81c14SSteve Longerbeam 	u8 mask, val;
157919a81c14SSteve Longerbeam 	int ret = 0;
158019a81c14SSteve Longerbeam 
1581e4359019SJacopo Mondi 	for (i = 0; i < regnum; ++i, ++regs) {
158219a81c14SSteve Longerbeam 		delay_ms = regs->delay_ms;
158319a81c14SSteve Longerbeam 		reg_addr = regs->reg_addr;
158419a81c14SSteve Longerbeam 		val = regs->val;
158519a81c14SSteve Longerbeam 		mask = regs->mask;
158619a81c14SSteve Longerbeam 
15873b987d70SLad Prabhakar 		/* remain in power down mode for DVP */
15883b987d70SLad Prabhakar 		if (regs->reg_addr == OV5640_REG_SYS_CTRL0 &&
15893b987d70SLad Prabhakar 		    val == OV5640_REG_SYS_CTRL0_SW_PWUP &&
15908e823f5cSJacopo Mondi 		    !ov5640_is_csi2(sensor))
15913b987d70SLad Prabhakar 			continue;
15923b987d70SLad Prabhakar 
159319a81c14SSteve Longerbeam 		if (mask)
159419a81c14SSteve Longerbeam 			ret = ov5640_mod_reg(sensor, reg_addr, mask, val);
159519a81c14SSteve Longerbeam 		else
159619a81c14SSteve Longerbeam 			ret = ov5640_write_reg(sensor, reg_addr, val);
159719a81c14SSteve Longerbeam 		if (ret)
159819a81c14SSteve Longerbeam 			break;
159919a81c14SSteve Longerbeam 
160019a81c14SSteve Longerbeam 		if (delay_ms)
160119a81c14SSteve Longerbeam 			usleep_range(1000 * delay_ms, 1000 * delay_ms + 100);
160219a81c14SSteve Longerbeam 	}
160319a81c14SSteve Longerbeam }
160419a81c14SSteve Longerbeam 
1605dc29a1c1SHugues Fruchet static int ov5640_set_autoexposure(struct ov5640_dev *sensor, bool on)
1606dc29a1c1SHugues Fruchet {
1607dc29a1c1SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
1608dc29a1c1SHugues Fruchet 			      BIT(0), on ? 0 : BIT(0));
1609dc29a1c1SHugues Fruchet }
1610dc29a1c1SHugues Fruchet 
161119a81c14SSteve Longerbeam /* read exposure, in number of line periods */
161219a81c14SSteve Longerbeam static int ov5640_get_exposure(struct ov5640_dev *sensor)
161319a81c14SSteve Longerbeam {
161419a81c14SSteve Longerbeam 	int exp, ret;
161519a81c14SSteve Longerbeam 	u8 temp;
161619a81c14SSteve Longerbeam 
161719a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_HI, &temp);
161819a81c14SSteve Longerbeam 	if (ret)
161919a81c14SSteve Longerbeam 		return ret;
162019a81c14SSteve Longerbeam 	exp = ((int)temp & 0x0f) << 16;
162119a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_MED, &temp);
162219a81c14SSteve Longerbeam 	if (ret)
162319a81c14SSteve Longerbeam 		return ret;
162419a81c14SSteve Longerbeam 	exp |= ((int)temp << 8);
162519a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_LO, &temp);
162619a81c14SSteve Longerbeam 	if (ret)
162719a81c14SSteve Longerbeam 		return ret;
162819a81c14SSteve Longerbeam 	exp |= (int)temp;
162919a81c14SSteve Longerbeam 
163019a81c14SSteve Longerbeam 	return exp >> 4;
163119a81c14SSteve Longerbeam }
163219a81c14SSteve Longerbeam 
163319a81c14SSteve Longerbeam /* write exposure, given number of line periods */
163419a81c14SSteve Longerbeam static int ov5640_set_exposure(struct ov5640_dev *sensor, u32 exposure)
163519a81c14SSteve Longerbeam {
163619a81c14SSteve Longerbeam 	int ret;
163719a81c14SSteve Longerbeam 
163819a81c14SSteve Longerbeam 	exposure <<= 4;
163919a81c14SSteve Longerbeam 
164019a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor,
164119a81c14SSteve Longerbeam 			       OV5640_REG_AEC_PK_EXPOSURE_LO,
164219a81c14SSteve Longerbeam 			       exposure & 0xff);
164319a81c14SSteve Longerbeam 	if (ret)
164419a81c14SSteve Longerbeam 		return ret;
164519a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor,
164619a81c14SSteve Longerbeam 			       OV5640_REG_AEC_PK_EXPOSURE_MED,
164719a81c14SSteve Longerbeam 			       (exposure >> 8) & 0xff);
164819a81c14SSteve Longerbeam 	if (ret)
164919a81c14SSteve Longerbeam 		return ret;
165019a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor,
165119a81c14SSteve Longerbeam 				OV5640_REG_AEC_PK_EXPOSURE_HI,
165219a81c14SSteve Longerbeam 				(exposure >> 16) & 0x0f);
165319a81c14SSteve Longerbeam }
165419a81c14SSteve Longerbeam 
165519a81c14SSteve Longerbeam static int ov5640_get_gain(struct ov5640_dev *sensor)
165619a81c14SSteve Longerbeam {
165719a81c14SSteve Longerbeam 	u16 gain;
165819a81c14SSteve Longerbeam 	int ret;
165919a81c14SSteve Longerbeam 
166019a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN, &gain);
166119a81c14SSteve Longerbeam 	if (ret)
166219a81c14SSteve Longerbeam 		return ret;
166319a81c14SSteve Longerbeam 
166419a81c14SSteve Longerbeam 	return gain & 0x3ff;
166519a81c14SSteve Longerbeam }
166619a81c14SSteve Longerbeam 
16673cca8ef5SHugues Fruchet static int ov5640_set_gain(struct ov5640_dev *sensor, int gain)
16683cca8ef5SHugues Fruchet {
16693cca8ef5SHugues Fruchet 	return ov5640_write_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN,
16703cca8ef5SHugues Fruchet 				  (u16)gain & 0x3ff);
16713cca8ef5SHugues Fruchet }
16723cca8ef5SHugues Fruchet 
16733cca8ef5SHugues Fruchet static int ov5640_set_autogain(struct ov5640_dev *sensor, bool on)
16743cca8ef5SHugues Fruchet {
16753cca8ef5SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
16763cca8ef5SHugues Fruchet 			      BIT(1), on ? 0 : BIT(1));
16773cca8ef5SHugues Fruchet }
16783cca8ef5SHugues Fruchet 
1679f22996dbSHugues Fruchet static int ov5640_set_stream_dvp(struct ov5640_dev *sensor, bool on)
1680f22996dbSHugues Fruchet {
16813b987d70SLad Prabhakar 	return ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0, on ?
16823b987d70SLad Prabhakar 				OV5640_REG_SYS_CTRL0_SW_PWUP :
16833b987d70SLad Prabhakar 				OV5640_REG_SYS_CTRL0_SW_PWDN);
1684f22996dbSHugues Fruchet }
1685f22996dbSHugues Fruchet 
1686f22996dbSHugues Fruchet static int ov5640_set_stream_mipi(struct ov5640_dev *sensor, bool on)
168719a81c14SSteve Longerbeam {
168819a81c14SSteve Longerbeam 	int ret;
168919a81c14SSteve Longerbeam 
1690aa4bb8b8SJacopo Mondi 	/*
1691aa4bb8b8SJacopo Mondi 	 * Enable/disable the MIPI interface
1692aa4bb8b8SJacopo Mondi 	 *
1693aa4bb8b8SJacopo Mondi 	 * 0x300e = on ? 0x45 : 0x40
1694aa4bb8b8SJacopo Mondi 	 *
1695aa4bb8b8SJacopo Mondi 	 * FIXME: the sensor manual (version 2.03) reports
1696aa4bb8b8SJacopo Mondi 	 * [7:5] = 000  : 1 data lane mode
1697aa4bb8b8SJacopo Mondi 	 * [7:5] = 001  : 2 data lanes mode
1698aa4bb8b8SJacopo Mondi 	 * But this settings do not work, while the following ones
1699aa4bb8b8SJacopo Mondi 	 * have been validated for 2 data lanes mode.
1700aa4bb8b8SJacopo Mondi 	 *
1701aa4bb8b8SJacopo Mondi 	 * [7:5] = 010	: 2 data lanes mode
1702aa4bb8b8SJacopo Mondi 	 * [4] = 0	: Power up MIPI HS Tx
1703aa4bb8b8SJacopo Mondi 	 * [3] = 0	: Power up MIPI LS Rx
1704aa4bb8b8SJacopo Mondi 	 * [2] = 1/0	: MIPI interface enable/disable
1705aa4bb8b8SJacopo Mondi 	 * [1:0] = 01/00: FIXME: 'debug'
1706aa4bb8b8SJacopo Mondi 	 */
1707aa4bb8b8SJacopo Mondi 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00,
1708aa4bb8b8SJacopo Mondi 			       on ? 0x45 : 0x40);
170919a81c14SSteve Longerbeam 	if (ret)
171019a81c14SSteve Longerbeam 		return ret;
171119a81c14SSteve Longerbeam 
171219a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_FRAME_CTRL01,
171319a81c14SSteve Longerbeam 				on ? 0x00 : 0x0f);
171419a81c14SSteve Longerbeam }
171519a81c14SSteve Longerbeam 
171619a81c14SSteve Longerbeam static int ov5640_get_sysclk(struct ov5640_dev *sensor)
171719a81c14SSteve Longerbeam {
171819a81c14SSteve Longerbeam 	 /* calculate sysclk */
171919a81c14SSteve Longerbeam 	u32 xvclk = sensor->xclk_freq / 10000;
172019a81c14SSteve Longerbeam 	u32 multiplier, prediv, VCO, sysdiv, pll_rdiv;
172119a81c14SSteve Longerbeam 	u32 sclk_rdiv_map[] = {1, 2, 4, 8};
172219a81c14SSteve Longerbeam 	u32 bit_div2x = 1, sclk_rdiv, sysclk;
172319a81c14SSteve Longerbeam 	u8 temp1, temp2;
172419a81c14SSteve Longerbeam 	int ret;
172519a81c14SSteve Longerbeam 
172619a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL0, &temp1);
172719a81c14SSteve Longerbeam 	if (ret)
172819a81c14SSteve Longerbeam 		return ret;
172919a81c14SSteve Longerbeam 	temp2 = temp1 & 0x0f;
173019a81c14SSteve Longerbeam 	if (temp2 == 8 || temp2 == 10)
173119a81c14SSteve Longerbeam 		bit_div2x = temp2 / 2;
173219a81c14SSteve Longerbeam 
173319a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL1, &temp1);
173419a81c14SSteve Longerbeam 	if (ret)
173519a81c14SSteve Longerbeam 		return ret;
173619a81c14SSteve Longerbeam 	sysdiv = temp1 >> 4;
173719a81c14SSteve Longerbeam 	if (sysdiv == 0)
173819a81c14SSteve Longerbeam 		sysdiv = 16;
173919a81c14SSteve Longerbeam 
174019a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL2, &temp1);
174119a81c14SSteve Longerbeam 	if (ret)
174219a81c14SSteve Longerbeam 		return ret;
174319a81c14SSteve Longerbeam 	multiplier = temp1;
174419a81c14SSteve Longerbeam 
174519a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL3, &temp1);
174619a81c14SSteve Longerbeam 	if (ret)
174719a81c14SSteve Longerbeam 		return ret;
174819a81c14SSteve Longerbeam 	prediv = temp1 & 0x0f;
174919a81c14SSteve Longerbeam 	pll_rdiv = ((temp1 >> 4) & 0x01) + 1;
175019a81c14SSteve Longerbeam 
175119a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, &temp1);
175219a81c14SSteve Longerbeam 	if (ret)
175319a81c14SSteve Longerbeam 		return ret;
175419a81c14SSteve Longerbeam 	temp2 = temp1 & 0x03;
175519a81c14SSteve Longerbeam 	sclk_rdiv = sclk_rdiv_map[temp2];
175619a81c14SSteve Longerbeam 
175719a81c14SSteve Longerbeam 	if (!prediv || !sysdiv || !pll_rdiv || !bit_div2x)
175819a81c14SSteve Longerbeam 		return -EINVAL;
175919a81c14SSteve Longerbeam 
176019a81c14SSteve Longerbeam 	VCO = xvclk * multiplier / prediv;
176119a81c14SSteve Longerbeam 
176219a81c14SSteve Longerbeam 	sysclk = VCO / sysdiv / pll_rdiv * 2 / bit_div2x / sclk_rdiv;
176319a81c14SSteve Longerbeam 
176419a81c14SSteve Longerbeam 	return sysclk;
176519a81c14SSteve Longerbeam }
176619a81c14SSteve Longerbeam 
176719a81c14SSteve Longerbeam static int ov5640_set_night_mode(struct ov5640_dev *sensor)
176819a81c14SSteve Longerbeam {
176919a81c14SSteve Longerbeam 	 /* read HTS from register settings */
177019a81c14SSteve Longerbeam 	u8 mode;
177119a81c14SSteve Longerbeam 	int ret;
177219a81c14SSteve Longerbeam 
177319a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_CTRL00, &mode);
177419a81c14SSteve Longerbeam 	if (ret)
177519a81c14SSteve Longerbeam 		return ret;
177619a81c14SSteve Longerbeam 	mode &= 0xfb;
177719a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL00, mode);
177819a81c14SSteve Longerbeam }
177919a81c14SSteve Longerbeam 
178019a81c14SSteve Longerbeam static int ov5640_get_hts(struct ov5640_dev *sensor)
178119a81c14SSteve Longerbeam {
178219a81c14SSteve Longerbeam 	/* read HTS from register settings */
178319a81c14SSteve Longerbeam 	u16 hts;
178419a81c14SSteve Longerbeam 	int ret;
178519a81c14SSteve Longerbeam 
178619a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_HTS, &hts);
178719a81c14SSteve Longerbeam 	if (ret)
178819a81c14SSteve Longerbeam 		return ret;
178919a81c14SSteve Longerbeam 	return hts;
179019a81c14SSteve Longerbeam }
179119a81c14SSteve Longerbeam 
179219a81c14SSteve Longerbeam static int ov5640_get_vts(struct ov5640_dev *sensor)
179319a81c14SSteve Longerbeam {
179419a81c14SSteve Longerbeam 	u16 vts;
179519a81c14SSteve Longerbeam 	int ret;
179619a81c14SSteve Longerbeam 
179719a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_VTS, &vts);
179819a81c14SSteve Longerbeam 	if (ret)
179919a81c14SSteve Longerbeam 		return ret;
180019a81c14SSteve Longerbeam 	return vts;
180119a81c14SSteve Longerbeam }
180219a81c14SSteve Longerbeam 
180319a81c14SSteve Longerbeam static int ov5640_set_vts(struct ov5640_dev *sensor, int vts)
180419a81c14SSteve Longerbeam {
180519a81c14SSteve Longerbeam 	return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, vts);
180619a81c14SSteve Longerbeam }
180719a81c14SSteve Longerbeam 
180819a81c14SSteve Longerbeam static int ov5640_get_light_freq(struct ov5640_dev *sensor)
180919a81c14SSteve Longerbeam {
181019a81c14SSteve Longerbeam 	/* get banding filter value */
181119a81c14SSteve Longerbeam 	int ret, light_freq = 0;
181219a81c14SSteve Longerbeam 	u8 temp, temp1;
181319a81c14SSteve Longerbeam 
181419a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL01, &temp);
181519a81c14SSteve Longerbeam 	if (ret)
181619a81c14SSteve Longerbeam 		return ret;
181719a81c14SSteve Longerbeam 
181819a81c14SSteve Longerbeam 	if (temp & 0x80) {
181919a81c14SSteve Longerbeam 		/* manual */
182019a81c14SSteve Longerbeam 		ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL00,
182119a81c14SSteve Longerbeam 				      &temp1);
182219a81c14SSteve Longerbeam 		if (ret)
182319a81c14SSteve Longerbeam 			return ret;
182419a81c14SSteve Longerbeam 		if (temp1 & 0x04) {
182519a81c14SSteve Longerbeam 			/* 50Hz */
182619a81c14SSteve Longerbeam 			light_freq = 50;
182719a81c14SSteve Longerbeam 		} else {
182819a81c14SSteve Longerbeam 			/* 60Hz */
182919a81c14SSteve Longerbeam 			light_freq = 60;
183019a81c14SSteve Longerbeam 		}
183119a81c14SSteve Longerbeam 	} else {
183219a81c14SSteve Longerbeam 		/* auto */
183319a81c14SSteve Longerbeam 		ret = ov5640_read_reg(sensor, OV5640_REG_SIGMADELTA_CTRL0C,
183419a81c14SSteve Longerbeam 				      &temp1);
183519a81c14SSteve Longerbeam 		if (ret)
183619a81c14SSteve Longerbeam 			return ret;
183719a81c14SSteve Longerbeam 
183819a81c14SSteve Longerbeam 		if (temp1 & 0x01) {
183919a81c14SSteve Longerbeam 			/* 50Hz */
184019a81c14SSteve Longerbeam 			light_freq = 50;
184119a81c14SSteve Longerbeam 		} else {
184219a81c14SSteve Longerbeam 			/* 60Hz */
184319a81c14SSteve Longerbeam 		}
184419a81c14SSteve Longerbeam 	}
184519a81c14SSteve Longerbeam 
184619a81c14SSteve Longerbeam 	return light_freq;
184719a81c14SSteve Longerbeam }
184819a81c14SSteve Longerbeam 
184919a81c14SSteve Longerbeam static int ov5640_set_bandingfilter(struct ov5640_dev *sensor)
185019a81c14SSteve Longerbeam {
185119a81c14SSteve Longerbeam 	u32 band_step60, max_band60, band_step50, max_band50, prev_vts;
185219a81c14SSteve Longerbeam 	int ret;
185319a81c14SSteve Longerbeam 
185419a81c14SSteve Longerbeam 	/* read preview PCLK */
185519a81c14SSteve Longerbeam 	ret = ov5640_get_sysclk(sensor);
185619a81c14SSteve Longerbeam 	if (ret < 0)
185719a81c14SSteve Longerbeam 		return ret;
185819a81c14SSteve Longerbeam 	if (ret == 0)
185919a81c14SSteve Longerbeam 		return -EINVAL;
186019a81c14SSteve Longerbeam 	sensor->prev_sysclk = ret;
186119a81c14SSteve Longerbeam 	/* read preview HTS */
186219a81c14SSteve Longerbeam 	ret = ov5640_get_hts(sensor);
186319a81c14SSteve Longerbeam 	if (ret < 0)
186419a81c14SSteve Longerbeam 		return ret;
186519a81c14SSteve Longerbeam 	if (ret == 0)
186619a81c14SSteve Longerbeam 		return -EINVAL;
186719a81c14SSteve Longerbeam 	sensor->prev_hts = ret;
186819a81c14SSteve Longerbeam 
186919a81c14SSteve Longerbeam 	/* read preview VTS */
187019a81c14SSteve Longerbeam 	ret = ov5640_get_vts(sensor);
187119a81c14SSteve Longerbeam 	if (ret < 0)
187219a81c14SSteve Longerbeam 		return ret;
187319a81c14SSteve Longerbeam 	prev_vts = ret;
187419a81c14SSteve Longerbeam 
187519a81c14SSteve Longerbeam 	/* calculate banding filter */
187619a81c14SSteve Longerbeam 	/* 60Hz */
187719a81c14SSteve Longerbeam 	band_step60 = sensor->prev_sysclk * 100 / sensor->prev_hts * 100 / 120;
187819a81c14SSteve Longerbeam 	ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B60_STEP, band_step60);
187919a81c14SSteve Longerbeam 	if (ret)
188019a81c14SSteve Longerbeam 		return ret;
188119a81c14SSteve Longerbeam 	if (!band_step60)
188219a81c14SSteve Longerbeam 		return -EINVAL;
188319a81c14SSteve Longerbeam 	max_band60 = (int)((prev_vts - 4) / band_step60);
188419a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0D, max_band60);
188519a81c14SSteve Longerbeam 	if (ret)
188619a81c14SSteve Longerbeam 		return ret;
188719a81c14SSteve Longerbeam 
188819a81c14SSteve Longerbeam 	/* 50Hz */
188919a81c14SSteve Longerbeam 	band_step50 = sensor->prev_sysclk * 100 / sensor->prev_hts;
189019a81c14SSteve Longerbeam 	ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B50_STEP, band_step50);
189119a81c14SSteve Longerbeam 	if (ret)
189219a81c14SSteve Longerbeam 		return ret;
189319a81c14SSteve Longerbeam 	if (!band_step50)
189419a81c14SSteve Longerbeam 		return -EINVAL;
189519a81c14SSteve Longerbeam 	max_band50 = (int)((prev_vts - 4) / band_step50);
189619a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0E, max_band50);
189719a81c14SSteve Longerbeam }
189819a81c14SSteve Longerbeam 
189919a81c14SSteve Longerbeam static int ov5640_set_ae_target(struct ov5640_dev *sensor, int target)
190019a81c14SSteve Longerbeam {
190119a81c14SSteve Longerbeam 	/* stable in high */
190219a81c14SSteve Longerbeam 	u32 fast_high, fast_low;
190319a81c14SSteve Longerbeam 	int ret;
190419a81c14SSteve Longerbeam 
190519a81c14SSteve Longerbeam 	sensor->ae_low = target * 23 / 25;	/* 0.92 */
190619a81c14SSteve Longerbeam 	sensor->ae_high = target * 27 / 25;	/* 1.08 */
190719a81c14SSteve Longerbeam 
190819a81c14SSteve Longerbeam 	fast_high = sensor->ae_high << 1;
190919a81c14SSteve Longerbeam 	if (fast_high > 255)
191019a81c14SSteve Longerbeam 		fast_high = 255;
191119a81c14SSteve Longerbeam 
191219a81c14SSteve Longerbeam 	fast_low = sensor->ae_low >> 1;
191319a81c14SSteve Longerbeam 
191419a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0F, sensor->ae_high);
191519a81c14SSteve Longerbeam 	if (ret)
191619a81c14SSteve Longerbeam 		return ret;
191719a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL10, sensor->ae_low);
191819a81c14SSteve Longerbeam 	if (ret)
191919a81c14SSteve Longerbeam 		return ret;
192019a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1B, sensor->ae_high);
192119a81c14SSteve Longerbeam 	if (ret)
192219a81c14SSteve Longerbeam 		return ret;
192319a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1E, sensor->ae_low);
192419a81c14SSteve Longerbeam 	if (ret)
192519a81c14SSteve Longerbeam 		return ret;
192619a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL11, fast_high);
192719a81c14SSteve Longerbeam 	if (ret)
192819a81c14SSteve Longerbeam 		return ret;
192919a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1F, fast_low);
193019a81c14SSteve Longerbeam }
193119a81c14SSteve Longerbeam 
1932c2c3f42dSHugues Fruchet static int ov5640_get_binning(struct ov5640_dev *sensor)
193319a81c14SSteve Longerbeam {
193419a81c14SSteve Longerbeam 	u8 temp;
193519a81c14SSteve Longerbeam 	int ret;
193619a81c14SSteve Longerbeam 
193719a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_TIMING_TC_REG21, &temp);
193819a81c14SSteve Longerbeam 	if (ret)
193919a81c14SSteve Longerbeam 		return ret;
1940c2c3f42dSHugues Fruchet 
1941c2c3f42dSHugues Fruchet 	return temp & BIT(0);
194219a81c14SSteve Longerbeam }
194319a81c14SSteve Longerbeam 
1944ce85705aSHugues Fruchet static int ov5640_set_binning(struct ov5640_dev *sensor, bool enable)
1945ce85705aSHugues Fruchet {
1946ce85705aSHugues Fruchet 	int ret;
1947ce85705aSHugues Fruchet 
1948ce85705aSHugues Fruchet 	/*
1949ce85705aSHugues Fruchet 	 * TIMING TC REG21:
1950ce85705aSHugues Fruchet 	 * - [0]:	Horizontal binning enable
1951ce85705aSHugues Fruchet 	 */
1952ce85705aSHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
1953ce85705aSHugues Fruchet 			     BIT(0), enable ? BIT(0) : 0);
1954ce85705aSHugues Fruchet 	if (ret)
1955ce85705aSHugues Fruchet 		return ret;
1956ce85705aSHugues Fruchet 	/*
1957ce85705aSHugues Fruchet 	 * TIMING TC REG20:
1958ce85705aSHugues Fruchet 	 * - [0]:	Undocumented, but hardcoded init sequences
1959ce85705aSHugues Fruchet 	 *		are always setting REG21/REG20 bit 0 to same value...
1960ce85705aSHugues Fruchet 	 */
1961ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20,
1962ce85705aSHugues Fruchet 			      BIT(0), enable ? BIT(0) : 0);
1963ce85705aSHugues Fruchet }
1964ce85705aSHugues Fruchet 
196519a81c14SSteve Longerbeam static int ov5640_set_virtual_channel(struct ov5640_dev *sensor)
196619a81c14SSteve Longerbeam {
19678670d70aSHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
196819a81c14SSteve Longerbeam 	u8 temp, channel = virtual_channel;
196919a81c14SSteve Longerbeam 	int ret;
197019a81c14SSteve Longerbeam 
19718670d70aSHugues Fruchet 	if (channel > 3) {
19728670d70aSHugues Fruchet 		dev_err(&client->dev,
19738670d70aSHugues Fruchet 			"%s: wrong virtual_channel parameter, expected (0..3), got %d\n",
19748670d70aSHugues Fruchet 			__func__, channel);
197519a81c14SSteve Longerbeam 		return -EINVAL;
19768670d70aSHugues Fruchet 	}
197719a81c14SSteve Longerbeam 
197819a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_DEBUG_MODE, &temp);
197919a81c14SSteve Longerbeam 	if (ret)
198019a81c14SSteve Longerbeam 		return ret;
198119a81c14SSteve Longerbeam 	temp &= ~(3 << 6);
198219a81c14SSteve Longerbeam 	temp |= (channel << 6);
198319a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_DEBUG_MODE, temp);
198419a81c14SSteve Longerbeam }
198519a81c14SSteve Longerbeam 
198619a81c14SSteve Longerbeam static const struct ov5640_mode_info *
198719a81c14SSteve Longerbeam ov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr,
198819a81c14SSteve Longerbeam 		 int width, int height, bool nearest)
198919a81c14SSteve Longerbeam {
19903c4a7372SHugues Fruchet 	const struct ov5640_mode_info *mode;
199119a81c14SSteve Longerbeam 
1992086c25f8SMaxime Ripard 	mode = v4l2_find_nearest_size(ov5640_mode_data,
1993086c25f8SMaxime Ripard 				      ARRAY_SIZE(ov5640_mode_data),
19945113d5b3SJacopo Mondi 				      width, height, width, height);
199519a81c14SSteve Longerbeam 
19963c4a7372SHugues Fruchet 	if (!mode ||
19973145efcdSJacopo Mondi 	    (!nearest &&
19985113d5b3SJacopo Mondi 	     (mode->width != width || mode->height != height)))
19993c4a7372SHugues Fruchet 		return NULL;
200019a81c14SSteve Longerbeam 
20015554c80eSAdam Ford 	/* Check to see if the current mode exceeds the max frame rate */
20025554c80eSAdam Ford 	if (ov5640_framerates[fr] > ov5640_framerates[mode->max_fps])
2003981e4454SBenoit Parrot 		return NULL;
2004981e4454SBenoit Parrot 
200519a81c14SSteve Longerbeam 	return mode;
200619a81c14SSteve Longerbeam }
200719a81c14SSteve Longerbeam 
200819a81c14SSteve Longerbeam /*
200919a81c14SSteve Longerbeam  * sensor changes between scaling and subsampling, go through
201019a81c14SSteve Longerbeam  * exposure calculation
201119a81c14SSteve Longerbeam  */
201241d8d7f5SHugues Fruchet static int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor,
201341d8d7f5SHugues Fruchet 					 const struct ov5640_mode_info *mode)
201419a81c14SSteve Longerbeam {
201519a81c14SSteve Longerbeam 	u32 prev_shutter, prev_gain16;
201619a81c14SSteve Longerbeam 	u32 cap_shutter, cap_gain16;
201719a81c14SSteve Longerbeam 	u32 cap_sysclk, cap_hts, cap_vts;
201819a81c14SSteve Longerbeam 	u32 light_freq, cap_bandfilt, cap_maxband;
201919a81c14SSteve Longerbeam 	u32 cap_gain16_shutter;
202019a81c14SSteve Longerbeam 	u8 average;
202119a81c14SSteve Longerbeam 	int ret;
202219a81c14SSteve Longerbeam 
202341d8d7f5SHugues Fruchet 	if (!mode->reg_data)
202419a81c14SSteve Longerbeam 		return -EINVAL;
202519a81c14SSteve Longerbeam 
202619a81c14SSteve Longerbeam 	/* read preview shutter */
202719a81c14SSteve Longerbeam 	ret = ov5640_get_exposure(sensor);
202819a81c14SSteve Longerbeam 	if (ret < 0)
202919a81c14SSteve Longerbeam 		return ret;
203019a81c14SSteve Longerbeam 	prev_shutter = ret;
2031c2c3f42dSHugues Fruchet 	ret = ov5640_get_binning(sensor);
203219a81c14SSteve Longerbeam 	if (ret < 0)
203319a81c14SSteve Longerbeam 		return ret;
203419a81c14SSteve Longerbeam 	if (ret && mode->id != OV5640_MODE_720P_1280_720 &&
203519a81c14SSteve Longerbeam 	    mode->id != OV5640_MODE_1080P_1920_1080)
203619a81c14SSteve Longerbeam 		prev_shutter *= 2;
203719a81c14SSteve Longerbeam 
203819a81c14SSteve Longerbeam 	/* read preview gain */
203919a81c14SSteve Longerbeam 	ret = ov5640_get_gain(sensor);
204019a81c14SSteve Longerbeam 	if (ret < 0)
204119a81c14SSteve Longerbeam 		return ret;
204219a81c14SSteve Longerbeam 	prev_gain16 = ret;
204319a81c14SSteve Longerbeam 
204419a81c14SSteve Longerbeam 	/* get average */
204519a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AVG_READOUT, &average);
204619a81c14SSteve Longerbeam 	if (ret)
204719a81c14SSteve Longerbeam 		return ret;
204819a81c14SSteve Longerbeam 
204919a81c14SSteve Longerbeam 	/* turn off night mode for capture */
205019a81c14SSteve Longerbeam 	ret = ov5640_set_night_mode(sensor);
205119a81c14SSteve Longerbeam 	if (ret < 0)
205219a81c14SSteve Longerbeam 		return ret;
205319a81c14SSteve Longerbeam 
205419a81c14SSteve Longerbeam 	/* Write capture setting */
2055e4359019SJacopo Mondi 	ov5640_load_regs(sensor, mode->reg_data, mode->reg_data_size);
2056e4359019SJacopo Mondi 	ret = ov5640_set_timings(sensor, mode);
205719a81c14SSteve Longerbeam 	if (ret < 0)
205819a81c14SSteve Longerbeam 		return ret;
205919a81c14SSteve Longerbeam 
206019a81c14SSteve Longerbeam 	/* read capture VTS */
206119a81c14SSteve Longerbeam 	ret = ov5640_get_vts(sensor);
206219a81c14SSteve Longerbeam 	if (ret < 0)
206319a81c14SSteve Longerbeam 		return ret;
206419a81c14SSteve Longerbeam 	cap_vts = ret;
206519a81c14SSteve Longerbeam 	ret = ov5640_get_hts(sensor);
206619a81c14SSteve Longerbeam 	if (ret < 0)
206719a81c14SSteve Longerbeam 		return ret;
206819a81c14SSteve Longerbeam 	if (ret == 0)
206919a81c14SSteve Longerbeam 		return -EINVAL;
207019a81c14SSteve Longerbeam 	cap_hts = ret;
207119a81c14SSteve Longerbeam 
207219a81c14SSteve Longerbeam 	ret = ov5640_get_sysclk(sensor);
207319a81c14SSteve Longerbeam 	if (ret < 0)
207419a81c14SSteve Longerbeam 		return ret;
207519a81c14SSteve Longerbeam 	if (ret == 0)
207619a81c14SSteve Longerbeam 		return -EINVAL;
207719a81c14SSteve Longerbeam 	cap_sysclk = ret;
207819a81c14SSteve Longerbeam 
207919a81c14SSteve Longerbeam 	/* calculate capture banding filter */
208019a81c14SSteve Longerbeam 	ret = ov5640_get_light_freq(sensor);
208119a81c14SSteve Longerbeam 	if (ret < 0)
208219a81c14SSteve Longerbeam 		return ret;
208319a81c14SSteve Longerbeam 	light_freq = ret;
208419a81c14SSteve Longerbeam 
208519a81c14SSteve Longerbeam 	if (light_freq == 60) {
208619a81c14SSteve Longerbeam 		/* 60Hz */
208719a81c14SSteve Longerbeam 		cap_bandfilt = cap_sysclk * 100 / cap_hts * 100 / 120;
208819a81c14SSteve Longerbeam 	} else {
208919a81c14SSteve Longerbeam 		/* 50Hz */
209019a81c14SSteve Longerbeam 		cap_bandfilt = cap_sysclk * 100 / cap_hts;
209119a81c14SSteve Longerbeam 	}
209219a81c14SSteve Longerbeam 
209319a81c14SSteve Longerbeam 	if (!sensor->prev_sysclk) {
209419a81c14SSteve Longerbeam 		ret = ov5640_get_sysclk(sensor);
209519a81c14SSteve Longerbeam 		if (ret < 0)
209619a81c14SSteve Longerbeam 			return ret;
209719a81c14SSteve Longerbeam 		if (ret == 0)
209819a81c14SSteve Longerbeam 			return -EINVAL;
209919a81c14SSteve Longerbeam 		sensor->prev_sysclk = ret;
210019a81c14SSteve Longerbeam 	}
210119a81c14SSteve Longerbeam 
210219a81c14SSteve Longerbeam 	if (!cap_bandfilt)
210319a81c14SSteve Longerbeam 		return -EINVAL;
210419a81c14SSteve Longerbeam 
210519a81c14SSteve Longerbeam 	cap_maxband = (int)((cap_vts - 4) / cap_bandfilt);
210619a81c14SSteve Longerbeam 
210719a81c14SSteve Longerbeam 	/* calculate capture shutter/gain16 */
210819a81c14SSteve Longerbeam 	if (average > sensor->ae_low && average < sensor->ae_high) {
210919a81c14SSteve Longerbeam 		/* in stable range */
211019a81c14SSteve Longerbeam 		cap_gain16_shutter =
211119a81c14SSteve Longerbeam 			prev_gain16 * prev_shutter *
211219a81c14SSteve Longerbeam 			cap_sysclk / sensor->prev_sysclk *
211319a81c14SSteve Longerbeam 			sensor->prev_hts / cap_hts *
211419a81c14SSteve Longerbeam 			sensor->ae_target / average;
211519a81c14SSteve Longerbeam 	} else {
211619a81c14SSteve Longerbeam 		cap_gain16_shutter =
211719a81c14SSteve Longerbeam 			prev_gain16 * prev_shutter *
211819a81c14SSteve Longerbeam 			cap_sysclk / sensor->prev_sysclk *
211919a81c14SSteve Longerbeam 			sensor->prev_hts / cap_hts;
212019a81c14SSteve Longerbeam 	}
212119a81c14SSteve Longerbeam 
212219a81c14SSteve Longerbeam 	/* gain to shutter */
212319a81c14SSteve Longerbeam 	if (cap_gain16_shutter < (cap_bandfilt * 16)) {
212419a81c14SSteve Longerbeam 		/* shutter < 1/100 */
212519a81c14SSteve Longerbeam 		cap_shutter = cap_gain16_shutter / 16;
212619a81c14SSteve Longerbeam 		if (cap_shutter < 1)
212719a81c14SSteve Longerbeam 			cap_shutter = 1;
212819a81c14SSteve Longerbeam 
212919a81c14SSteve Longerbeam 		cap_gain16 = cap_gain16_shutter / cap_shutter;
213019a81c14SSteve Longerbeam 		if (cap_gain16 < 16)
213119a81c14SSteve Longerbeam 			cap_gain16 = 16;
213219a81c14SSteve Longerbeam 	} else {
213319a81c14SSteve Longerbeam 		if (cap_gain16_shutter > (cap_bandfilt * cap_maxband * 16)) {
213419a81c14SSteve Longerbeam 			/* exposure reach max */
213519a81c14SSteve Longerbeam 			cap_shutter = cap_bandfilt * cap_maxband;
213619a81c14SSteve Longerbeam 			if (!cap_shutter)
213719a81c14SSteve Longerbeam 				return -EINVAL;
213819a81c14SSteve Longerbeam 
213919a81c14SSteve Longerbeam 			cap_gain16 = cap_gain16_shutter / cap_shutter;
214019a81c14SSteve Longerbeam 		} else {
214119a81c14SSteve Longerbeam 			/* 1/100 < (cap_shutter = n/100) =< max */
214219a81c14SSteve Longerbeam 			cap_shutter =
214319a81c14SSteve Longerbeam 				((int)(cap_gain16_shutter / 16 / cap_bandfilt))
214419a81c14SSteve Longerbeam 				* cap_bandfilt;
214519a81c14SSteve Longerbeam 			if (!cap_shutter)
214619a81c14SSteve Longerbeam 				return -EINVAL;
214719a81c14SSteve Longerbeam 
214819a81c14SSteve Longerbeam 			cap_gain16 = cap_gain16_shutter / cap_shutter;
214919a81c14SSteve Longerbeam 		}
215019a81c14SSteve Longerbeam 	}
215119a81c14SSteve Longerbeam 
215219a81c14SSteve Longerbeam 	/* set capture gain */
21533cca8ef5SHugues Fruchet 	ret = ov5640_set_gain(sensor, cap_gain16);
215419a81c14SSteve Longerbeam 	if (ret)
215519a81c14SSteve Longerbeam 		return ret;
215619a81c14SSteve Longerbeam 
215719a81c14SSteve Longerbeam 	/* write capture shutter */
215819a81c14SSteve Longerbeam 	if (cap_shutter > (cap_vts - 4)) {
215919a81c14SSteve Longerbeam 		cap_vts = cap_shutter + 4;
216019a81c14SSteve Longerbeam 		ret = ov5640_set_vts(sensor, cap_vts);
216119a81c14SSteve Longerbeam 		if (ret < 0)
216219a81c14SSteve Longerbeam 			return ret;
216319a81c14SSteve Longerbeam 	}
216419a81c14SSteve Longerbeam 
216519a81c14SSteve Longerbeam 	/* set exposure */
21663cca8ef5SHugues Fruchet 	return ov5640_set_exposure(sensor, cap_shutter);
216719a81c14SSteve Longerbeam }
216819a81c14SSteve Longerbeam 
216919a81c14SSteve Longerbeam /*
217019a81c14SSteve Longerbeam  * if sensor changes inside scaling or subsampling
217119a81c14SSteve Longerbeam  * change mode directly
217219a81c14SSteve Longerbeam  */
217319a81c14SSteve Longerbeam static int ov5640_set_mode_direct(struct ov5640_dev *sensor,
21743cca8ef5SHugues Fruchet 				  const struct ov5640_mode_info *mode)
217519a81c14SSteve Longerbeam {
217641d8d7f5SHugues Fruchet 	if (!mode->reg_data)
217719a81c14SSteve Longerbeam 		return -EINVAL;
217819a81c14SSteve Longerbeam 
217919a81c14SSteve Longerbeam 	/* Write capture setting */
2180e4359019SJacopo Mondi 	ov5640_load_regs(sensor, mode->reg_data, mode->reg_data_size);
2181e4359019SJacopo Mondi 	return ov5640_set_timings(sensor, mode);
218219a81c14SSteve Longerbeam }
218319a81c14SSteve Longerbeam 
2184985cdcb0SHugues Fruchet static int ov5640_set_mode(struct ov5640_dev *sensor)
218519a81c14SSteve Longerbeam {
218619a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode = sensor->current_mode;
2187985cdcb0SHugues Fruchet 	const struct ov5640_mode_info *orig_mode = sensor->last_mode;
218819a81c14SSteve Longerbeam 	enum ov5640_downsize_mode dn_mode, orig_dn_mode;
21893cca8ef5SHugues Fruchet 	bool auto_gain = sensor->ctrls.auto_gain->val == 1;
2190dc29a1c1SHugues Fruchet 	bool auto_exp =  sensor->ctrls.auto_exp->val == V4L2_EXPOSURE_AUTO;
219119a81c14SSteve Longerbeam 	int ret;
219219a81c14SSteve Longerbeam 
219319a81c14SSteve Longerbeam 	dn_mode = mode->dn_mode;
219419a81c14SSteve Longerbeam 	orig_dn_mode = orig_mode->dn_mode;
219519a81c14SSteve Longerbeam 
219619a81c14SSteve Longerbeam 	/* auto gain and exposure must be turned off when changing modes */
21973cca8ef5SHugues Fruchet 	if (auto_gain) {
21983cca8ef5SHugues Fruchet 		ret = ov5640_set_autogain(sensor, false);
219919a81c14SSteve Longerbeam 		if (ret)
220019a81c14SSteve Longerbeam 			return ret;
22013cca8ef5SHugues Fruchet 	}
2202bf4a4b51SMaxime Ripard 
22033cca8ef5SHugues Fruchet 	if (auto_exp) {
2204dc29a1c1SHugues Fruchet 		ret = ov5640_set_autoexposure(sensor, false);
220519a81c14SSteve Longerbeam 		if (ret)
22063cca8ef5SHugues Fruchet 			goto restore_auto_gain;
22073cca8ef5SHugues Fruchet 	}
220819a81c14SSteve Longerbeam 
22096c957ed7SJacopo Mondi 	if (ov5640_is_csi2(sensor))
22106c957ed7SJacopo Mondi 		ret = ov5640_set_mipi_pclk(sensor);
22116c957ed7SJacopo Mondi 	else
22126c957ed7SJacopo Mondi 		ret = ov5640_set_dvp_pclk(sensor);
2213aa288248SMaxime Ripard 	if (ret < 0)
2214aa288248SMaxime Ripard 		return 0;
2215aa288248SMaxime Ripard 
221619a81c14SSteve Longerbeam 	if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) ||
221719a81c14SSteve Longerbeam 	    (dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) {
221819a81c14SSteve Longerbeam 		/*
221919a81c14SSteve Longerbeam 		 * change between subsampling and scaling
22203cca8ef5SHugues Fruchet 		 * go through exposure calculation
222119a81c14SSteve Longerbeam 		 */
222219a81c14SSteve Longerbeam 		ret = ov5640_set_mode_exposure_calc(sensor, mode);
222319a81c14SSteve Longerbeam 	} else {
222419a81c14SSteve Longerbeam 		/*
222519a81c14SSteve Longerbeam 		 * change inside subsampling or scaling
222619a81c14SSteve Longerbeam 		 * download firmware directly
222719a81c14SSteve Longerbeam 		 */
22283cca8ef5SHugues Fruchet 		ret = ov5640_set_mode_direct(sensor, mode);
222919a81c14SSteve Longerbeam 	}
223019a81c14SSteve Longerbeam 	if (ret < 0)
22313cca8ef5SHugues Fruchet 		goto restore_auto_exp_gain;
22323cca8ef5SHugues Fruchet 
22333cca8ef5SHugues Fruchet 	/* restore auto gain and exposure */
22343cca8ef5SHugues Fruchet 	if (auto_gain)
22353cca8ef5SHugues Fruchet 		ov5640_set_autogain(sensor, true);
22363cca8ef5SHugues Fruchet 	if (auto_exp)
22373cca8ef5SHugues Fruchet 		ov5640_set_autoexposure(sensor, true);
223819a81c14SSteve Longerbeam 
2239ce85705aSHugues Fruchet 	ret = ov5640_set_binning(sensor, dn_mode != SCALING);
2240ce85705aSHugues Fruchet 	if (ret < 0)
2241ce85705aSHugues Fruchet 		return ret;
224219a81c14SSteve Longerbeam 	ret = ov5640_set_ae_target(sensor, sensor->ae_target);
224319a81c14SSteve Longerbeam 	if (ret < 0)
224419a81c14SSteve Longerbeam 		return ret;
224519a81c14SSteve Longerbeam 	ret = ov5640_get_light_freq(sensor);
224619a81c14SSteve Longerbeam 	if (ret < 0)
224719a81c14SSteve Longerbeam 		return ret;
224819a81c14SSteve Longerbeam 	ret = ov5640_set_bandingfilter(sensor);
224919a81c14SSteve Longerbeam 	if (ret < 0)
225019a81c14SSteve Longerbeam 		return ret;
225119a81c14SSteve Longerbeam 	ret = ov5640_set_virtual_channel(sensor);
225219a81c14SSteve Longerbeam 	if (ret < 0)
225319a81c14SSteve Longerbeam 		return ret;
225419a81c14SSteve Longerbeam 
225519a81c14SSteve Longerbeam 	sensor->pending_mode_change = false;
2256985cdcb0SHugues Fruchet 	sensor->last_mode = mode;
225719a81c14SSteve Longerbeam 
225819a81c14SSteve Longerbeam 	return 0;
22593cca8ef5SHugues Fruchet 
22603cca8ef5SHugues Fruchet restore_auto_exp_gain:
22613cca8ef5SHugues Fruchet 	if (auto_exp)
22623cca8ef5SHugues Fruchet 		ov5640_set_autoexposure(sensor, true);
22633cca8ef5SHugues Fruchet restore_auto_gain:
22643cca8ef5SHugues Fruchet 	if (auto_gain)
22653cca8ef5SHugues Fruchet 		ov5640_set_autogain(sensor, true);
22663cca8ef5SHugues Fruchet 
22673cca8ef5SHugues Fruchet 	return ret;
226819a81c14SSteve Longerbeam }
226919a81c14SSteve Longerbeam 
227019ad26f9SAkinobu Mita static int ov5640_set_framefmt(struct ov5640_dev *sensor,
227119ad26f9SAkinobu Mita 			       struct v4l2_mbus_framefmt *format);
227219ad26f9SAkinobu Mita 
227319a81c14SSteve Longerbeam /* restore the last set video mode after chip power-on */
227419a81c14SSteve Longerbeam static int ov5640_restore_mode(struct ov5640_dev *sensor)
227519a81c14SSteve Longerbeam {
227619a81c14SSteve Longerbeam 	int ret;
227719a81c14SSteve Longerbeam 
227819a81c14SSteve Longerbeam 	/* first load the initial register values */
2279e4359019SJacopo Mondi 	ov5640_load_regs(sensor, ov5640_init_setting,
2280e4359019SJacopo Mondi 			 ARRAY_SIZE(ov5640_init_setting));
228119a81c14SSteve Longerbeam 
22828f57c2f8SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
22837851fe7aSMaxime Ripard 			     (ilog2(OV5640_SCLK2X_ROOT_DIV) << 2) |
22847851fe7aSMaxime Ripard 			     ilog2(OV5640_SCLK_ROOT_DIV));
22858f57c2f8SMaxime Ripard 	if (ret)
22868f57c2f8SMaxime Ripard 		return ret;
22878f57c2f8SMaxime Ripard 
228819a81c14SSteve Longerbeam 	/* now restore the last capture mode */
2289985cdcb0SHugues Fruchet 	ret = ov5640_set_mode(sensor);
229019ad26f9SAkinobu Mita 	if (ret < 0)
229119ad26f9SAkinobu Mita 		return ret;
229219ad26f9SAkinobu Mita 
229319ad26f9SAkinobu Mita 	return ov5640_set_framefmt(sensor, &sensor->fmt);
229419a81c14SSteve Longerbeam }
229519a81c14SSteve Longerbeam 
229619a81c14SSteve Longerbeam static void ov5640_power(struct ov5640_dev *sensor, bool enable)
229719a81c14SSteve Longerbeam {
22981fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->pwdn_gpio, enable ? 0 : 1);
229919a81c14SSteve Longerbeam }
230019a81c14SSteve Longerbeam 
230119a81c14SSteve Longerbeam static void ov5640_reset(struct ov5640_dev *sensor)
230219a81c14SSteve Longerbeam {
230319a81c14SSteve Longerbeam 	if (!sensor->reset_gpio)
230419a81c14SSteve Longerbeam 		return;
230519a81c14SSteve Longerbeam 
23061fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 0);
230719a81c14SSteve Longerbeam 
230819a81c14SSteve Longerbeam 	/* camera power cycle */
230919a81c14SSteve Longerbeam 	ov5640_power(sensor, false);
231019a81c14SSteve Longerbeam 	usleep_range(5000, 10000);
231119a81c14SSteve Longerbeam 	ov5640_power(sensor, true);
231219a81c14SSteve Longerbeam 	usleep_range(5000, 10000);
231319a81c14SSteve Longerbeam 
23141fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 1);
231519a81c14SSteve Longerbeam 	usleep_range(1000, 2000);
231619a81c14SSteve Longerbeam 
23171fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 0);
23181d4c41f3SLoic Poulain 	usleep_range(20000, 25000);
231919a81c14SSteve Longerbeam }
232019a81c14SSteve Longerbeam 
23210f7acb52SHugues Fruchet static int ov5640_set_power_on(struct ov5640_dev *sensor)
232219a81c14SSteve Longerbeam {
23230f7acb52SHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
23240f7acb52SHugues Fruchet 	int ret;
232519a81c14SSteve Longerbeam 
23260f7acb52SHugues Fruchet 	ret = clk_prepare_enable(sensor->xclk);
23270f7acb52SHugues Fruchet 	if (ret) {
23280f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to enable clock\n",
23290f7acb52SHugues Fruchet 			__func__);
23300f7acb52SHugues Fruchet 		return ret;
23310f7acb52SHugues Fruchet 	}
233219a81c14SSteve Longerbeam 
233319a81c14SSteve Longerbeam 	ret = regulator_bulk_enable(OV5640_NUM_SUPPLIES,
233419a81c14SSteve Longerbeam 				    sensor->supplies);
23350f7acb52SHugues Fruchet 	if (ret) {
23360f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to enable regulators\n",
23370f7acb52SHugues Fruchet 			__func__);
233819a81c14SSteve Longerbeam 		goto xclk_off;
23390f7acb52SHugues Fruchet 	}
234019a81c14SSteve Longerbeam 
234119a81c14SSteve Longerbeam 	ov5640_reset(sensor);
234219a81c14SSteve Longerbeam 	ov5640_power(sensor, true);
234319a81c14SSteve Longerbeam 
234419a81c14SSteve Longerbeam 	ret = ov5640_init_slave_id(sensor);
234519a81c14SSteve Longerbeam 	if (ret)
234619a81c14SSteve Longerbeam 		goto power_off;
234719a81c14SSteve Longerbeam 
23480f7acb52SHugues Fruchet 	return 0;
23490f7acb52SHugues Fruchet 
23500f7acb52SHugues Fruchet power_off:
23510f7acb52SHugues Fruchet 	ov5640_power(sensor, false);
23520f7acb52SHugues Fruchet 	regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies);
23530f7acb52SHugues Fruchet xclk_off:
23540f7acb52SHugues Fruchet 	clk_disable_unprepare(sensor->xclk);
23550f7acb52SHugues Fruchet 	return ret;
23560f7acb52SHugues Fruchet }
23570f7acb52SHugues Fruchet 
23580f7acb52SHugues Fruchet static void ov5640_set_power_off(struct ov5640_dev *sensor)
23590f7acb52SHugues Fruchet {
23600f7acb52SHugues Fruchet 	ov5640_power(sensor, false);
23610f7acb52SHugues Fruchet 	regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies);
23620f7acb52SHugues Fruchet 	clk_disable_unprepare(sensor->xclk);
23630f7acb52SHugues Fruchet }
23640f7acb52SHugues Fruchet 
2365b1751ae6SLad Prabhakar static int ov5640_set_power_mipi(struct ov5640_dev *sensor, bool on)
2366b1751ae6SLad Prabhakar {
2367b1751ae6SLad Prabhakar 	int ret;
2368b1751ae6SLad Prabhakar 
2369b1751ae6SLad Prabhakar 	if (!on) {
2370b1751ae6SLad Prabhakar 		/* Reset MIPI bus settings to their default values. */
2371b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
2372b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x04);
2373b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x00);
2374b1751ae6SLad Prabhakar 		return 0;
2375b1751ae6SLad Prabhakar 	}
2376b1751ae6SLad Prabhakar 
2377b1751ae6SLad Prabhakar 	/*
2378b1751ae6SLad Prabhakar 	 * Power up MIPI HS Tx and LS Rx; 2 data lanes mode
2379b1751ae6SLad Prabhakar 	 *
2380b1751ae6SLad Prabhakar 	 * 0x300e = 0x40
2381b1751ae6SLad Prabhakar 	 * [7:5] = 010	: 2 data lanes mode (see FIXME note in
2382b1751ae6SLad Prabhakar 	 *		  "ov5640_set_stream_mipi()")
2383b1751ae6SLad Prabhakar 	 * [4] = 0	: Power up MIPI HS Tx
2384b1751ae6SLad Prabhakar 	 * [3] = 0	: Power up MIPI LS Rx
2385b1751ae6SLad Prabhakar 	 * [2] = 0	: MIPI interface disabled
2386b1751ae6SLad Prabhakar 	 */
2387b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x40);
2388b1751ae6SLad Prabhakar 	if (ret)
2389b1751ae6SLad Prabhakar 		return ret;
2390b1751ae6SLad Prabhakar 
2391b1751ae6SLad Prabhakar 	/*
2392b1751ae6SLad Prabhakar 	 * Gate clock and set LP11 in 'no packets mode' (idle)
2393b1751ae6SLad Prabhakar 	 *
2394b1751ae6SLad Prabhakar 	 * 0x4800 = 0x24
2395b1751ae6SLad Prabhakar 	 * [5] = 1	: Gate clock when 'no packets'
2396b1751ae6SLad Prabhakar 	 * [2] = 1	: MIPI bus in LP11 when 'no packets'
2397b1751ae6SLad Prabhakar 	 */
2398b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x24);
2399b1751ae6SLad Prabhakar 	if (ret)
2400b1751ae6SLad Prabhakar 		return ret;
2401b1751ae6SLad Prabhakar 
2402b1751ae6SLad Prabhakar 	/*
2403b1751ae6SLad Prabhakar 	 * Set data lanes and clock in LP11 when 'sleeping'
2404b1751ae6SLad Prabhakar 	 *
2405b1751ae6SLad Prabhakar 	 * 0x3019 = 0x70
2406b1751ae6SLad Prabhakar 	 * [6] = 1	: MIPI data lane 2 in LP11 when 'sleeping'
2407b1751ae6SLad Prabhakar 	 * [5] = 1	: MIPI data lane 1 in LP11 when 'sleeping'
2408b1751ae6SLad Prabhakar 	 * [4] = 1	: MIPI clock lane in LP11 when 'sleeping'
2409b1751ae6SLad Prabhakar 	 */
2410b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x70);
2411b1751ae6SLad Prabhakar 	if (ret)
2412b1751ae6SLad Prabhakar 		return ret;
2413b1751ae6SLad Prabhakar 
2414b1751ae6SLad Prabhakar 	/* Give lanes some time to coax into LP11 state. */
2415b1751ae6SLad Prabhakar 	usleep_range(500, 1000);
2416b1751ae6SLad Prabhakar 
2417b1751ae6SLad Prabhakar 	return 0;
2418b1751ae6SLad Prabhakar }
2419b1751ae6SLad Prabhakar 
2420576f5d4bSLad Prabhakar static int ov5640_set_power_dvp(struct ov5640_dev *sensor, bool on)
2421576f5d4bSLad Prabhakar {
2422311a6408SLad Prabhakar 	unsigned int flags = sensor->ep.bus.parallel.flags;
242368579b32SHugues Fruchet 	bool bt656 = sensor->ep.bus_type == V4L2_MBUS_BT656;
242468579b32SHugues Fruchet 	u8 polarities = 0;
2425576f5d4bSLad Prabhakar 	int ret;
2426576f5d4bSLad Prabhakar 
2427576f5d4bSLad Prabhakar 	if (!on) {
2428576f5d4bSLad Prabhakar 		/* Reset settings to their default values. */
242968579b32SHugues Fruchet 		ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00, 0x00);
2430311a6408SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
2431311a6408SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, 0x20);
2432576f5d4bSLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01, 0x00);
2433576f5d4bSLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0x00);
2434576f5d4bSLad Prabhakar 		return 0;
2435576f5d4bSLad Prabhakar 	}
2436576f5d4bSLad Prabhakar 
2437576f5d4bSLad Prabhakar 	/*
2438311a6408SLad Prabhakar 	 * Note about parallel port configuration.
2439311a6408SLad Prabhakar 	 *
2440311a6408SLad Prabhakar 	 * When configured in parallel mode, the OV5640 will
2441311a6408SLad Prabhakar 	 * output 10 bits data on DVP data lines [9:0].
2442311a6408SLad Prabhakar 	 * If only 8 bits data are wanted, the 8 bits data lines
2443311a6408SLad Prabhakar 	 * of the camera interface must be physically connected
2444311a6408SLad Prabhakar 	 * on the DVP data lines [9:2].
2445311a6408SLad Prabhakar 	 *
2446311a6408SLad Prabhakar 	 * Control lines polarity can be configured through
2447311a6408SLad Prabhakar 	 * devicetree endpoint control lines properties.
2448311a6408SLad Prabhakar 	 * If no endpoint control lines properties are set,
2449311a6408SLad Prabhakar 	 * polarity will be as below:
2450311a6408SLad Prabhakar 	 * - VSYNC:	active high
2451311a6408SLad Prabhakar 	 * - HREF:	active low
2452311a6408SLad Prabhakar 	 * - PCLK:	active low
245368579b32SHugues Fruchet 	 *
245468579b32SHugues Fruchet 	 * VSYNC & HREF are not configured if BT656 bus mode is selected
2455311a6408SLad Prabhakar 	 */
245668579b32SHugues Fruchet 
245768579b32SHugues Fruchet 	/*
245868579b32SHugues Fruchet 	 * BT656 embedded synchronization configuration
245968579b32SHugues Fruchet 	 *
246068579b32SHugues Fruchet 	 * CCIR656 CTRL00
246168579b32SHugues Fruchet 	 * - [7]:	SYNC code selection (0: auto generate sync code,
246268579b32SHugues Fruchet 	 *		1: sync code from regs 0x4732-0x4735)
246368579b32SHugues Fruchet 	 * - [6]:	f value in CCIR656 SYNC code when fixed f value
246468579b32SHugues Fruchet 	 * - [5]:	Fixed f value
246568579b32SHugues Fruchet 	 * - [4:3]:	Blank toggle data options (00: data=1'h040/1'h200,
246668579b32SHugues Fruchet 	 *		01: data from regs 0x4736-0x4738, 10: always keep 0)
246768579b32SHugues Fruchet 	 * - [1]:	Clip data disable
246868579b32SHugues Fruchet 	 * - [0]:	CCIR656 mode enable
246968579b32SHugues Fruchet 	 *
247068579b32SHugues Fruchet 	 * Default CCIR656 SAV/EAV mode with default codes
247168579b32SHugues Fruchet 	 * SAV=0xff000080 & EAV=0xff00009d is enabled here with settings:
247268579b32SHugues Fruchet 	 * - CCIR656 mode enable
247368579b32SHugues Fruchet 	 * - auto generation of sync codes
247468579b32SHugues Fruchet 	 * - blank toggle data 1'h040/1'h200
247568579b32SHugues Fruchet 	 * - clip reserved data (0x00 & 0xff changed to 0x01 & 0xfe)
247668579b32SHugues Fruchet 	 */
247768579b32SHugues Fruchet 	ret = ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00,
247868579b32SHugues Fruchet 			       bt656 ? 0x01 : 0x00);
247968579b32SHugues Fruchet 	if (ret)
248068579b32SHugues Fruchet 		return ret;
248168579b32SHugues Fruchet 
2482311a6408SLad Prabhakar 	/*
2483311a6408SLad Prabhakar 	 * configure parallel port control lines polarity
2484311a6408SLad Prabhakar 	 *
2485311a6408SLad Prabhakar 	 * POLARITY CTRL0
2486311a6408SLad Prabhakar 	 * - [5]:	PCLK polarity (0: active low, 1: active high)
2487311a6408SLad Prabhakar 	 * - [1]:	HREF polarity (0: active low, 1: active high)
2488311a6408SLad Prabhakar 	 * - [0]:	VSYNC polarity (mismatch here between
2489311a6408SLad Prabhakar 	 *		datasheet and hardware, 0 is active high
2490311a6408SLad Prabhakar 	 *		and 1 is active low...)
2491311a6408SLad Prabhakar 	 */
249268579b32SHugues Fruchet 	if (!bt656) {
2493311a6408SLad Prabhakar 		if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
249468579b32SHugues Fruchet 			polarities |= BIT(1);
2495311a6408SLad Prabhakar 		if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
249668579b32SHugues Fruchet 			polarities |= BIT(0);
249768579b32SHugues Fruchet 	}
249868579b32SHugues Fruchet 	if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
249968579b32SHugues Fruchet 		polarities |= BIT(5);
2500311a6408SLad Prabhakar 
250168579b32SHugues Fruchet 	ret = ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, polarities);
2502311a6408SLad Prabhakar 	if (ret)
2503311a6408SLad Prabhakar 		return ret;
2504311a6408SLad Prabhakar 
2505311a6408SLad Prabhakar 	/*
250668579b32SHugues Fruchet 	 * powerdown MIPI TX/RX PHY & enable DVP
2507311a6408SLad Prabhakar 	 *
2508311a6408SLad Prabhakar 	 * MIPI CONTROL 00
250968579b32SHugues Fruchet 	 * [4] = 1	: Power down MIPI HS Tx
251068579b32SHugues Fruchet 	 * [3] = 1	: Power down MIPI LS Rx
251168579b32SHugues Fruchet 	 * [2] = 0	: DVP enable (MIPI disable)
2512311a6408SLad Prabhakar 	 */
2513311a6408SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x18);
2514311a6408SLad Prabhakar 	if (ret)
2515311a6408SLad Prabhakar 		return ret;
2516311a6408SLad Prabhakar 
2517311a6408SLad Prabhakar 	/*
2518576f5d4bSLad Prabhakar 	 * enable VSYNC/HREF/PCLK DVP control lines
2519576f5d4bSLad Prabhakar 	 * & D[9:6] DVP data lines
2520576f5d4bSLad Prabhakar 	 *
2521576f5d4bSLad Prabhakar 	 * PAD OUTPUT ENABLE 01
2522576f5d4bSLad Prabhakar 	 * - 6:		VSYNC output enable
2523576f5d4bSLad Prabhakar 	 * - 5:		HREF output enable
2524576f5d4bSLad Prabhakar 	 * - 4:		PCLK output enable
2525576f5d4bSLad Prabhakar 	 * - [3:0]:	D[9:6] output enable
2526576f5d4bSLad Prabhakar 	 */
25274039b037SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01,
252868579b32SHugues Fruchet 			       bt656 ? 0x1f : 0x7f);
2529576f5d4bSLad Prabhakar 	if (ret)
2530576f5d4bSLad Prabhakar 		return ret;
2531576f5d4bSLad Prabhakar 
2532576f5d4bSLad Prabhakar 	/*
2533576f5d4bSLad Prabhakar 	 * enable D[5:0] DVP data lines
2534576f5d4bSLad Prabhakar 	 *
2535576f5d4bSLad Prabhakar 	 * PAD OUTPUT ENABLE 02
2536576f5d4bSLad Prabhakar 	 * - [7:2]:	D[5:0] output enable
2537576f5d4bSLad Prabhakar 	 */
2538576f5d4bSLad Prabhakar 	return ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0xfc);
2539576f5d4bSLad Prabhakar }
2540576f5d4bSLad Prabhakar 
25410f7acb52SHugues Fruchet static int ov5640_set_power(struct ov5640_dev *sensor, bool on)
25420f7acb52SHugues Fruchet {
25430f7acb52SHugues Fruchet 	int ret = 0;
25440f7acb52SHugues Fruchet 
25450f7acb52SHugues Fruchet 	if (on) {
25460f7acb52SHugues Fruchet 		ret = ov5640_set_power_on(sensor);
25470f7acb52SHugues Fruchet 		if (ret)
25480f7acb52SHugues Fruchet 			return ret;
25490f7acb52SHugues Fruchet 
255019a81c14SSteve Longerbeam 		ret = ov5640_restore_mode(sensor);
255119a81c14SSteve Longerbeam 		if (ret)
255219a81c14SSteve Longerbeam 			goto power_off;
2553b1751ae6SLad Prabhakar 	}
255419a81c14SSteve Longerbeam 
2555576f5d4bSLad Prabhakar 	if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY)
2556b1751ae6SLad Prabhakar 		ret = ov5640_set_power_mipi(sensor, on);
2557576f5d4bSLad Prabhakar 	else
2558576f5d4bSLad Prabhakar 		ret = ov5640_set_power_dvp(sensor, on);
2559b1751ae6SLad Prabhakar 	if (ret)
2560b1751ae6SLad Prabhakar 		goto power_off;
2561aa4bb8b8SJacopo Mondi 
2562b1751ae6SLad Prabhakar 	if (!on)
2563aa4bb8b8SJacopo Mondi 		ov5640_set_power_off(sensor);
256419a81c14SSteve Longerbeam 
256519a81c14SSteve Longerbeam 	return 0;
256619a81c14SSteve Longerbeam 
256719a81c14SSteve Longerbeam power_off:
25680f7acb52SHugues Fruchet 	ov5640_set_power_off(sensor);
256919a81c14SSteve Longerbeam 	return ret;
257019a81c14SSteve Longerbeam }
257119a81c14SSteve Longerbeam 
257219a81c14SSteve Longerbeam /* --------------- Subdev Operations --------------- */
257319a81c14SSteve Longerbeam 
257419a81c14SSteve Longerbeam static int ov5640_s_power(struct v4l2_subdev *sd, int on)
257519a81c14SSteve Longerbeam {
257619a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
257719a81c14SSteve Longerbeam 	int ret = 0;
257819a81c14SSteve Longerbeam 
257919a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
258019a81c14SSteve Longerbeam 
258119a81c14SSteve Longerbeam 	/*
258219a81c14SSteve Longerbeam 	 * If the power count is modified from 0 to != 0 or from != 0 to 0,
258319a81c14SSteve Longerbeam 	 * update the power state.
258419a81c14SSteve Longerbeam 	 */
258519a81c14SSteve Longerbeam 	if (sensor->power_count == !on) {
258619a81c14SSteve Longerbeam 		ret = ov5640_set_power(sensor, !!on);
258719a81c14SSteve Longerbeam 		if (ret)
258819a81c14SSteve Longerbeam 			goto out;
258919a81c14SSteve Longerbeam 	}
259019a81c14SSteve Longerbeam 
259119a81c14SSteve Longerbeam 	/* Update the power count. */
259219a81c14SSteve Longerbeam 	sensor->power_count += on ? 1 : -1;
259319a81c14SSteve Longerbeam 	WARN_ON(sensor->power_count < 0);
259419a81c14SSteve Longerbeam out:
259519a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
259619a81c14SSteve Longerbeam 
259719a81c14SSteve Longerbeam 	if (on && !ret && sensor->power_count == 1) {
259819a81c14SSteve Longerbeam 		/* restore controls */
259919a81c14SSteve Longerbeam 		ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
260019a81c14SSteve Longerbeam 	}
260119a81c14SSteve Longerbeam 
260219a81c14SSteve Longerbeam 	return ret;
260319a81c14SSteve Longerbeam }
260419a81c14SSteve Longerbeam 
260519a81c14SSteve Longerbeam static int ov5640_try_frame_interval(struct ov5640_dev *sensor,
260619a81c14SSteve Longerbeam 				     struct v4l2_fract *fi,
260719a81c14SSteve Longerbeam 				     u32 width, u32 height)
260819a81c14SSteve Longerbeam {
260919a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
26106530a5ebSJagan Teki 	enum ov5640_frame_rate rate = OV5640_15_FPS;
2611f6cc192fSMaxime Ripard 	int minfps, maxfps, best_fps, fps;
2612f6cc192fSMaxime Ripard 	int i;
261319a81c14SSteve Longerbeam 
261419a81c14SSteve Longerbeam 	minfps = ov5640_framerates[OV5640_15_FPS];
2615e823fb16SMaxime Ripard 	maxfps = ov5640_framerates[OV5640_60_FPS];
261619a81c14SSteve Longerbeam 
261719a81c14SSteve Longerbeam 	if (fi->numerator == 0) {
261819a81c14SSteve Longerbeam 		fi->denominator = maxfps;
261919a81c14SSteve Longerbeam 		fi->numerator = 1;
2620e823fb16SMaxime Ripard 		rate = OV5640_60_FPS;
2621e823fb16SMaxime Ripard 		goto find_mode;
262219a81c14SSteve Longerbeam 	}
262319a81c14SSteve Longerbeam 
2624f6cc192fSMaxime Ripard 	fps = clamp_val(DIV_ROUND_CLOSEST(fi->denominator, fi->numerator),
2625f6cc192fSMaxime Ripard 			minfps, maxfps);
2626f6cc192fSMaxime Ripard 
2627f6cc192fSMaxime Ripard 	best_fps = minfps;
2628f6cc192fSMaxime Ripard 	for (i = 0; i < ARRAY_SIZE(ov5640_framerates); i++) {
2629f6cc192fSMaxime Ripard 		int curr_fps = ov5640_framerates[i];
2630f6cc192fSMaxime Ripard 
2631f6cc192fSMaxime Ripard 		if (abs(curr_fps - fps) < abs(best_fps - fps)) {
2632f6cc192fSMaxime Ripard 			best_fps = curr_fps;
2633f6cc192fSMaxime Ripard 			rate = i;
2634f6cc192fSMaxime Ripard 		}
2635f6cc192fSMaxime Ripard 	}
263619a81c14SSteve Longerbeam 
263719a81c14SSteve Longerbeam 	fi->numerator = 1;
2638f6cc192fSMaxime Ripard 	fi->denominator = best_fps;
263919a81c14SSteve Longerbeam 
2640e823fb16SMaxime Ripard find_mode:
26415a3ad937SMaxime Ripard 	mode = ov5640_find_mode(sensor, rate, width, height, false);
26425a3ad937SMaxime Ripard 	return mode ? rate : -EINVAL;
264319a81c14SSteve Longerbeam }
264419a81c14SSteve Longerbeam 
264519a81c14SSteve Longerbeam static int ov5640_get_fmt(struct v4l2_subdev *sd,
26460d346d2aSTomi Valkeinen 			  struct v4l2_subdev_state *sd_state,
264719a81c14SSteve Longerbeam 			  struct v4l2_subdev_format *format)
264819a81c14SSteve Longerbeam {
264919a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
265019a81c14SSteve Longerbeam 	struct v4l2_mbus_framefmt *fmt;
265119a81c14SSteve Longerbeam 
265219a81c14SSteve Longerbeam 	if (format->pad != 0)
265319a81c14SSteve Longerbeam 		return -EINVAL;
265419a81c14SSteve Longerbeam 
265519a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
265619a81c14SSteve Longerbeam 
265719a81c14SSteve Longerbeam 	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
26580d346d2aSTomi Valkeinen 		fmt = v4l2_subdev_get_try_format(&sensor->sd, sd_state,
265919a81c14SSteve Longerbeam 						 format->pad);
266019a81c14SSteve Longerbeam 	else
266119a81c14SSteve Longerbeam 		fmt = &sensor->fmt;
266219a81c14SSteve Longerbeam 
266319a81c14SSteve Longerbeam 	format->format = *fmt;
266419a81c14SSteve Longerbeam 
266519a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
266619a81c14SSteve Longerbeam 
266719a81c14SSteve Longerbeam 	return 0;
266819a81c14SSteve Longerbeam }
266919a81c14SSteve Longerbeam 
267019a81c14SSteve Longerbeam static int ov5640_try_fmt_internal(struct v4l2_subdev *sd,
267119a81c14SSteve Longerbeam 				   struct v4l2_mbus_framefmt *fmt,
267219a81c14SSteve Longerbeam 				   enum ov5640_frame_rate fr,
267319a81c14SSteve Longerbeam 				   const struct ov5640_mode_info **new_mode)
267419a81c14SSteve Longerbeam {
267519a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
267619a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
2677e3ee691dSHugues Fruchet 	int i;
267819a81c14SSteve Longerbeam 
267919a81c14SSteve Longerbeam 	mode = ov5640_find_mode(sensor, fr, fmt->width, fmt->height, true);
268019a81c14SSteve Longerbeam 	if (!mode)
268119a81c14SSteve Longerbeam 		return -EINVAL;
26825113d5b3SJacopo Mondi 	fmt->width = mode->width;
26835113d5b3SJacopo Mondi 	fmt->height = mode->height;
268419a81c14SSteve Longerbeam 
268519a81c14SSteve Longerbeam 	if (new_mode)
268619a81c14SSteve Longerbeam 		*new_mode = mode;
2687e3ee691dSHugues Fruchet 
2688e3ee691dSHugues Fruchet 	for (i = 0; i < ARRAY_SIZE(ov5640_formats); i++)
2689e3ee691dSHugues Fruchet 		if (ov5640_formats[i].code == fmt->code)
2690e3ee691dSHugues Fruchet 			break;
2691e3ee691dSHugues Fruchet 	if (i >= ARRAY_SIZE(ov5640_formats))
2692e6441fdeSHugues Fruchet 		i = 0;
2693e6441fdeSHugues Fruchet 
2694e6441fdeSHugues Fruchet 	fmt->code = ov5640_formats[i].code;
2695e6441fdeSHugues Fruchet 	fmt->colorspace = ov5640_formats[i].colorspace;
2696e6441fdeSHugues Fruchet 	fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
2697e6441fdeSHugues Fruchet 	fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
2698e6441fdeSHugues Fruchet 	fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
2699e3ee691dSHugues Fruchet 
270019a81c14SSteve Longerbeam 	return 0;
270119a81c14SSteve Longerbeam }
270219a81c14SSteve Longerbeam 
27033c28588fSJacopo Mondi static int ov5640_update_pixel_rate(struct ov5640_dev *sensor)
27043c28588fSJacopo Mondi {
27053c28588fSJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
27063c28588fSJacopo Mondi 	enum ov5640_pixel_rate_id pixel_rate_id = mode->pixel_rate;
27073c28588fSJacopo Mondi 	struct v4l2_mbus_framefmt *fmt = &sensor->fmt;
270832979f67SJacopo Mondi 	const struct ov5640_timings *timings;
2709*bce93b82SJacopo Mondi 	s32 exposure_val, exposure_max;
271032979f67SJacopo Mondi 	unsigned int hblank;
27113c28588fSJacopo Mondi 	unsigned int i = 0;
27123c28588fSJacopo Mondi 	u32 pixel_rate;
27133c28588fSJacopo Mondi 	s64 link_freq;
27143c28588fSJacopo Mondi 	u32 num_lanes;
27153c28588fSJacopo Mondi 	u32 bpp;
27163c28588fSJacopo Mondi 
27173c28588fSJacopo Mondi 	/*
27183c28588fSJacopo Mondi 	 * Update the pixel rate control value.
27193c28588fSJacopo Mondi 	 *
27203c28588fSJacopo Mondi 	 * For DVP mode, maintain the pixel rate calculation using fixed FPS.
27213c28588fSJacopo Mondi 	 */
27223c28588fSJacopo Mondi 	if (!ov5640_is_csi2(sensor)) {
27233c28588fSJacopo Mondi 		__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate,
27243c28588fSJacopo Mondi 					 ov5640_calc_pixel_rate(sensor));
27253c28588fSJacopo Mondi 
27263c28588fSJacopo Mondi 		return 0;
27273c28588fSJacopo Mondi 	}
27283c28588fSJacopo Mondi 
27293c28588fSJacopo Mondi 	/*
27303c28588fSJacopo Mondi 	 * The MIPI CSI-2 link frequency should comply with the CSI-2
27313c28588fSJacopo Mondi 	 * specification and be lower than 1GHz.
27323c28588fSJacopo Mondi 	 *
27333c28588fSJacopo Mondi 	 * Start from the suggested pixel_rate for the current mode and
27343c28588fSJacopo Mondi 	 * progressively slow it down if it exceeds 1GHz.
27353c28588fSJacopo Mondi 	 */
27363c28588fSJacopo Mondi 	num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes;
27373c28588fSJacopo Mondi 	bpp = ov5640_code_to_bpp(fmt->code);
27383c28588fSJacopo Mondi 	do {
27393c28588fSJacopo Mondi 		pixel_rate = ov5640_pixel_rates[pixel_rate_id];
27403c28588fSJacopo Mondi 		link_freq = pixel_rate * bpp / (2 * num_lanes);
27413c28588fSJacopo Mondi 	} while (link_freq >= 1000000000U &&
27423c28588fSJacopo Mondi 		 ++pixel_rate_id < OV5640_NUM_PIXEL_RATES);
27433c28588fSJacopo Mondi 
27443c28588fSJacopo Mondi 	sensor->current_link_freq = link_freq;
27453c28588fSJacopo Mondi 
27463c28588fSJacopo Mondi 	/*
27473c28588fSJacopo Mondi 	 * Higher link rates require the clock tree to be programmed with
27483c28588fSJacopo Mondi 	 * 'mipi_div' = 1; this has the effect of halving the actual output
27493c28588fSJacopo Mondi 	 * pixel rate in the MIPI domain.
27503c28588fSJacopo Mondi 	 *
27513c28588fSJacopo Mondi 	 * Adjust the pixel rate and link frequency control value to report it
27523c28588fSJacopo Mondi 	 * correctly to userspace.
27533c28588fSJacopo Mondi 	 */
27543c28588fSJacopo Mondi 	if (link_freq > OV5640_LINK_RATE_MAX) {
27553c28588fSJacopo Mondi 		pixel_rate /= 2;
27563c28588fSJacopo Mondi 		link_freq /= 2;
27573c28588fSJacopo Mondi 	}
27583c28588fSJacopo Mondi 
27593c28588fSJacopo Mondi 	for (i = 0; i < ARRAY_SIZE(ov5640_csi2_link_freqs); ++i) {
27603c28588fSJacopo Mondi 		if (ov5640_csi2_link_freqs[i] == link_freq)
27613c28588fSJacopo Mondi 			break;
27623c28588fSJacopo Mondi 	}
27633c28588fSJacopo Mondi 	WARN_ON(i == ARRAY_SIZE(ov5640_csi2_link_freqs));
27643c28588fSJacopo Mondi 
27653c28588fSJacopo Mondi 	__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, pixel_rate);
27663c28588fSJacopo Mondi 	__v4l2_ctrl_s_ctrl(sensor->ctrls.link_freq, i);
27673c28588fSJacopo Mondi 
276832979f67SJacopo Mondi 	timings = ov5640_timings(sensor, mode);
276932979f67SJacopo Mondi 	hblank = timings->htot - mode->width;
277032979f67SJacopo Mondi 	__v4l2_ctrl_modify_range(sensor->ctrls.hblank,
277132979f67SJacopo Mondi 				 hblank, hblank, 1, hblank);
277232979f67SJacopo Mondi 
2773*bce93b82SJacopo Mondi 	__v4l2_ctrl_modify_range(sensor->ctrls.vblank, OV5640_MIN_VBLANK,
2774*bce93b82SJacopo Mondi 				 OV5640_MAX_VTS - mode->height, 1,
2775*bce93b82SJacopo Mondi 				 timings->vblank_def);
2776*bce93b82SJacopo Mondi 	__v4l2_ctrl_s_ctrl(sensor->ctrls.vblank, timings->vblank_def);
2777*bce93b82SJacopo Mondi 
2778*bce93b82SJacopo Mondi 	exposure_max = timings->crop.height + timings->vblank_def - 4;
2779*bce93b82SJacopo Mondi 	exposure_val = clamp_t(s32, sensor->ctrls.exposure->val,
2780*bce93b82SJacopo Mondi 			       sensor->ctrls.exposure->minimum,
2781*bce93b82SJacopo Mondi 			       exposure_max);
2782*bce93b82SJacopo Mondi 	__v4l2_ctrl_modify_range(sensor->ctrls.exposure,
2783*bce93b82SJacopo Mondi 				 sensor->ctrls.exposure->minimum,
2784*bce93b82SJacopo Mondi 				 exposure_max, 1, exposure_val);
2785*bce93b82SJacopo Mondi 
27863c28588fSJacopo Mondi 	return 0;
27873c28588fSJacopo Mondi }
27883c28588fSJacopo Mondi 
278919a81c14SSteve Longerbeam static int ov5640_set_fmt(struct v4l2_subdev *sd,
27900d346d2aSTomi Valkeinen 			  struct v4l2_subdev_state *sd_state,
279119a81c14SSteve Longerbeam 			  struct v4l2_subdev_format *format)
279219a81c14SSteve Longerbeam {
279319a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
279419a81c14SSteve Longerbeam 	const struct ov5640_mode_info *new_mode;
2795e6441fdeSHugues Fruchet 	struct v4l2_mbus_framefmt *mbus_fmt = &format->format;
279619a81c14SSteve Longerbeam 	int ret;
279719a81c14SSteve Longerbeam 
279819a81c14SSteve Longerbeam 	if (format->pad != 0)
279919a81c14SSteve Longerbeam 		return -EINVAL;
280019a81c14SSteve Longerbeam 
280119a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
280219a81c14SSteve Longerbeam 
280319a81c14SSteve Longerbeam 	if (sensor->streaming) {
280419a81c14SSteve Longerbeam 		ret = -EBUSY;
280519a81c14SSteve Longerbeam 		goto out;
280619a81c14SSteve Longerbeam 	}
280719a81c14SSteve Longerbeam 
2808e6441fdeSHugues Fruchet 	ret = ov5640_try_fmt_internal(sd, mbus_fmt,
280919a81c14SSteve Longerbeam 				      sensor->current_fr, &new_mode);
281019a81c14SSteve Longerbeam 	if (ret)
281119a81c14SSteve Longerbeam 		goto out;
281219a81c14SSteve Longerbeam 
2813e738f5ddSMirela Rabulea 	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
2814e738f5ddSMirela Rabulea 		*v4l2_subdev_get_try_format(sd, sd_state, 0) = *mbus_fmt;
2815e738f5ddSMirela Rabulea 		goto out;
2816e738f5ddSMirela Rabulea 	}
281719a81c14SSteve Longerbeam 
28186949d864SHugues Fruchet 	if (new_mode != sensor->current_mode) {
281919a81c14SSteve Longerbeam 		sensor->current_mode = new_mode;
282019a81c14SSteve Longerbeam 		sensor->pending_mode_change = true;
28216949d864SHugues Fruchet 	}
282207115449SJacopo Mondi 	if (mbus_fmt->code != sensor->fmt.code)
2823fb98e29fSHugues Fruchet 		sensor->pending_fmt_change = true;
282407115449SJacopo Mondi 
2825e738f5ddSMirela Rabulea 	/* update format even if code is unchanged, resolution might change */
2826e738f5ddSMirela Rabulea 	sensor->fmt = *mbus_fmt;
2827e738f5ddSMirela Rabulea 
28283c28588fSJacopo Mondi 	ov5640_update_pixel_rate(sensor);
28293c28588fSJacopo Mondi 
283019a81c14SSteve Longerbeam out:
283119a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
283219a81c14SSteve Longerbeam 	return ret;
283319a81c14SSteve Longerbeam }
283419a81c14SSteve Longerbeam 
2835e3ee691dSHugues Fruchet static int ov5640_set_framefmt(struct ov5640_dev *sensor,
2836e3ee691dSHugues Fruchet 			       struct v4l2_mbus_framefmt *format)
2837e3ee691dSHugues Fruchet {
2838e3ee691dSHugues Fruchet 	int ret = 0;
2839d47c4126SHugues Fruchet 	bool is_jpeg = false;
2840b7ed3abdSLoic Poulain 	u8 fmt, mux;
2841e3ee691dSHugues Fruchet 
2842e3ee691dSHugues Fruchet 	switch (format->code) {
28431536fbdbSXavier Roumegue 	case MEDIA_BUS_FMT_UYVY8_1X16:
2844e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_UYVY8_2X8:
2845e3ee691dSHugues Fruchet 		/* YUV422, UYVY */
2846b7ed3abdSLoic Poulain 		fmt = 0x3f;
2847b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_YUV422;
2848e3ee691dSHugues Fruchet 		break;
28491536fbdbSXavier Roumegue 	case MEDIA_BUS_FMT_YUYV8_1X16:
2850e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_YUYV8_2X8:
2851e3ee691dSHugues Fruchet 		/* YUV422, YUYV */
2852b7ed3abdSLoic Poulain 		fmt = 0x30;
2853b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_YUV422;
2854e3ee691dSHugues Fruchet 		break;
2855e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_RGB565_2X8_LE:
2856e3ee691dSHugues Fruchet 		/* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */
2857b7ed3abdSLoic Poulain 		fmt = 0x6F;
2858b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RGB;
2859e3ee691dSHugues Fruchet 		break;
2860e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_RGB565_2X8_BE:
2861e3ee691dSHugues Fruchet 		/* RGB565 {r[4:0],g[5:3]},{g[2:0],b[4:0]} */
2862b7ed3abdSLoic Poulain 		fmt = 0x61;
2863b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RGB;
2864e3ee691dSHugues Fruchet 		break;
2865d47c4126SHugues Fruchet 	case MEDIA_BUS_FMT_JPEG_1X8:
2866d47c4126SHugues Fruchet 		/* YUV422, YUYV */
2867b7ed3abdSLoic Poulain 		fmt = 0x30;
2868b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_YUV422;
2869d47c4126SHugues Fruchet 		is_jpeg = true;
2870d47c4126SHugues Fruchet 		break;
2871b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SBGGR8_1X8:
2872b7ed3abdSLoic Poulain 		/* Raw, BGBG... / GRGR... */
2873b7ed3abdSLoic Poulain 		fmt = 0x00;
2874b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2875b7ed3abdSLoic Poulain 		break;
2876b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SGBRG8_1X8:
2877b7ed3abdSLoic Poulain 		/* Raw bayer, GBGB... / RGRG... */
2878b7ed3abdSLoic Poulain 		fmt = 0x01;
2879b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2880b7ed3abdSLoic Poulain 		break;
2881b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SGRBG8_1X8:
2882b7ed3abdSLoic Poulain 		/* Raw bayer, GRGR... / BGBG... */
2883b7ed3abdSLoic Poulain 		fmt = 0x02;
2884b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2885b7ed3abdSLoic Poulain 		break;
2886b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SRGGB8_1X8:
2887b7ed3abdSLoic Poulain 		/* Raw bayer, RGRG... / GBGB... */
2888b7ed3abdSLoic Poulain 		fmt = 0x03;
2889b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2890b7ed3abdSLoic Poulain 		break;
2891e3ee691dSHugues Fruchet 	default:
2892e3ee691dSHugues Fruchet 		return -EINVAL;
2893e3ee691dSHugues Fruchet 	}
2894e3ee691dSHugues Fruchet 
2895e3ee691dSHugues Fruchet 	/* FORMAT CONTROL00: YUV and RGB formatting */
2896b7ed3abdSLoic Poulain 	ret = ov5640_write_reg(sensor, OV5640_REG_FORMAT_CONTROL00, fmt);
2897e3ee691dSHugues Fruchet 	if (ret)
2898e3ee691dSHugues Fruchet 		return ret;
2899e3ee691dSHugues Fruchet 
2900e3ee691dSHugues Fruchet 	/* FORMAT MUX CONTROL: ISP YUV or RGB */
2901b7ed3abdSLoic Poulain 	ret = ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL, mux);
2902d47c4126SHugues Fruchet 	if (ret)
2903d47c4126SHugues Fruchet 		return ret;
2904d47c4126SHugues Fruchet 
2905d47c4126SHugues Fruchet 	/*
2906d47c4126SHugues Fruchet 	 * TIMING TC REG21:
2907d47c4126SHugues Fruchet 	 * - [5]:	JPEG enable
2908d47c4126SHugues Fruchet 	 */
2909d47c4126SHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
2910d47c4126SHugues Fruchet 			     BIT(5), is_jpeg ? BIT(5) : 0);
2911d47c4126SHugues Fruchet 	if (ret)
2912d47c4126SHugues Fruchet 		return ret;
2913d47c4126SHugues Fruchet 
2914d47c4126SHugues Fruchet 	/*
2915d47c4126SHugues Fruchet 	 * SYSTEM RESET02:
2916d47c4126SHugues Fruchet 	 * - [4]:	Reset JFIFO
2917d47c4126SHugues Fruchet 	 * - [3]:	Reset SFIFO
2918d47c4126SHugues Fruchet 	 * - [2]:	Reset JPEG
2919d47c4126SHugues Fruchet 	 */
2920d47c4126SHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_RESET02,
2921d47c4126SHugues Fruchet 			     BIT(4) | BIT(3) | BIT(2),
2922d47c4126SHugues Fruchet 			     is_jpeg ? 0 : (BIT(4) | BIT(3) | BIT(2)));
2923d47c4126SHugues Fruchet 	if (ret)
2924d47c4126SHugues Fruchet 		return ret;
2925d47c4126SHugues Fruchet 
2926d47c4126SHugues Fruchet 	/*
2927d47c4126SHugues Fruchet 	 * CLOCK ENABLE02:
2928d47c4126SHugues Fruchet 	 * - [5]:	Enable JPEG 2x clock
2929d47c4126SHugues Fruchet 	 * - [3]:	Enable JPEG clock
2930d47c4126SHugues Fruchet 	 */
2931d47c4126SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_SYS_CLOCK_ENABLE02,
2932d47c4126SHugues Fruchet 			      BIT(5) | BIT(3),
2933d47c4126SHugues Fruchet 			      is_jpeg ? (BIT(5) | BIT(3)) : 0);
2934e3ee691dSHugues Fruchet }
293519a81c14SSteve Longerbeam 
293619a81c14SSteve Longerbeam /*
293719a81c14SSteve Longerbeam  * Sensor Controls.
293819a81c14SSteve Longerbeam  */
293919a81c14SSteve Longerbeam 
294019a81c14SSteve Longerbeam static int ov5640_set_ctrl_hue(struct ov5640_dev *sensor, int value)
294119a81c14SSteve Longerbeam {
294219a81c14SSteve Longerbeam 	int ret;
294319a81c14SSteve Longerbeam 
294419a81c14SSteve Longerbeam 	if (value) {
294519a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
294619a81c14SSteve Longerbeam 				     BIT(0), BIT(0));
294719a81c14SSteve Longerbeam 		if (ret)
294819a81c14SSteve Longerbeam 			return ret;
294919a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_SDE_CTRL1, value);
295019a81c14SSteve Longerbeam 	} else {
295119a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(0), 0);
295219a81c14SSteve Longerbeam 	}
295319a81c14SSteve Longerbeam 
295419a81c14SSteve Longerbeam 	return ret;
295519a81c14SSteve Longerbeam }
295619a81c14SSteve Longerbeam 
295719a81c14SSteve Longerbeam static int ov5640_set_ctrl_contrast(struct ov5640_dev *sensor, int value)
295819a81c14SSteve Longerbeam {
295919a81c14SSteve Longerbeam 	int ret;
296019a81c14SSteve Longerbeam 
296119a81c14SSteve Longerbeam 	if (value) {
296219a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
296319a81c14SSteve Longerbeam 				     BIT(2), BIT(2));
296419a81c14SSteve Longerbeam 		if (ret)
296519a81c14SSteve Longerbeam 			return ret;
296619a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL5,
296719a81c14SSteve Longerbeam 				       value & 0xff);
296819a81c14SSteve Longerbeam 	} else {
296919a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(2), 0);
297019a81c14SSteve Longerbeam 	}
297119a81c14SSteve Longerbeam 
297219a81c14SSteve Longerbeam 	return ret;
297319a81c14SSteve Longerbeam }
297419a81c14SSteve Longerbeam 
297519a81c14SSteve Longerbeam static int ov5640_set_ctrl_saturation(struct ov5640_dev *sensor, int value)
297619a81c14SSteve Longerbeam {
297719a81c14SSteve Longerbeam 	int ret;
297819a81c14SSteve Longerbeam 
297919a81c14SSteve Longerbeam 	if (value) {
298019a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
298119a81c14SSteve Longerbeam 				     BIT(1), BIT(1));
298219a81c14SSteve Longerbeam 		if (ret)
298319a81c14SSteve Longerbeam 			return ret;
298419a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL3,
298519a81c14SSteve Longerbeam 				       value & 0xff);
298619a81c14SSteve Longerbeam 		if (ret)
298719a81c14SSteve Longerbeam 			return ret;
298819a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL4,
298919a81c14SSteve Longerbeam 				       value & 0xff);
299019a81c14SSteve Longerbeam 	} else {
299119a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(1), 0);
299219a81c14SSteve Longerbeam 	}
299319a81c14SSteve Longerbeam 
299419a81c14SSteve Longerbeam 	return ret;
299519a81c14SSteve Longerbeam }
299619a81c14SSteve Longerbeam 
299719a81c14SSteve Longerbeam static int ov5640_set_ctrl_white_balance(struct ov5640_dev *sensor, int awb)
299819a81c14SSteve Longerbeam {
299919a81c14SSteve Longerbeam 	int ret;
300019a81c14SSteve Longerbeam 
300119a81c14SSteve Longerbeam 	ret = ov5640_mod_reg(sensor, OV5640_REG_AWB_MANUAL_CTRL,
300219a81c14SSteve Longerbeam 			     BIT(0), awb ? 0 : 1);
300319a81c14SSteve Longerbeam 	if (ret)
300419a81c14SSteve Longerbeam 		return ret;
300519a81c14SSteve Longerbeam 
300619a81c14SSteve Longerbeam 	if (!awb) {
300719a81c14SSteve Longerbeam 		u16 red = (u16)sensor->ctrls.red_balance->val;
300819a81c14SSteve Longerbeam 		u16 blue = (u16)sensor->ctrls.blue_balance->val;
300919a81c14SSteve Longerbeam 
301019a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_R_GAIN, red);
301119a81c14SSteve Longerbeam 		if (ret)
301219a81c14SSteve Longerbeam 			return ret;
301319a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_B_GAIN, blue);
301419a81c14SSteve Longerbeam 	}
301519a81c14SSteve Longerbeam 
301619a81c14SSteve Longerbeam 	return ret;
301719a81c14SSteve Longerbeam }
301819a81c14SSteve Longerbeam 
30193cca8ef5SHugues Fruchet static int ov5640_set_ctrl_exposure(struct ov5640_dev *sensor,
30203cca8ef5SHugues Fruchet 				    enum v4l2_exposure_auto_type auto_exposure)
302119a81c14SSteve Longerbeam {
302219a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
30233cca8ef5SHugues Fruchet 	bool auto_exp = (auto_exposure == V4L2_EXPOSURE_AUTO);
302419a81c14SSteve Longerbeam 	int ret = 0;
302519a81c14SSteve Longerbeam 
302619a81c14SSteve Longerbeam 	if (ctrls->auto_exp->is_new) {
30273cca8ef5SHugues Fruchet 		ret = ov5640_set_autoexposure(sensor, auto_exp);
302819a81c14SSteve Longerbeam 		if (ret)
302919a81c14SSteve Longerbeam 			return ret;
303019a81c14SSteve Longerbeam 	}
303119a81c14SSteve Longerbeam 
30323cca8ef5SHugues Fruchet 	if (!auto_exp && ctrls->exposure->is_new) {
303319a81c14SSteve Longerbeam 		u16 max_exp;
303419a81c14SSteve Longerbeam 
303519a81c14SSteve Longerbeam 		ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_VTS,
303619a81c14SSteve Longerbeam 					&max_exp);
303719a81c14SSteve Longerbeam 		if (ret)
303819a81c14SSteve Longerbeam 			return ret;
303919a81c14SSteve Longerbeam 		ret = ov5640_get_vts(sensor);
304019a81c14SSteve Longerbeam 		if (ret < 0)
304119a81c14SSteve Longerbeam 			return ret;
304219a81c14SSteve Longerbeam 		max_exp += ret;
30436146fde3SHugues Fruchet 		ret = 0;
304419a81c14SSteve Longerbeam 
304519a81c14SSteve Longerbeam 		if (ctrls->exposure->val < max_exp)
304619a81c14SSteve Longerbeam 			ret = ov5640_set_exposure(sensor, ctrls->exposure->val);
304719a81c14SSteve Longerbeam 	}
304819a81c14SSteve Longerbeam 
304919a81c14SSteve Longerbeam 	return ret;
305019a81c14SSteve Longerbeam }
305119a81c14SSteve Longerbeam 
30523cca8ef5SHugues Fruchet static int ov5640_set_ctrl_gain(struct ov5640_dev *sensor, bool auto_gain)
305319a81c14SSteve Longerbeam {
305419a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
305519a81c14SSteve Longerbeam 	int ret = 0;
305619a81c14SSteve Longerbeam 
305719a81c14SSteve Longerbeam 	if (ctrls->auto_gain->is_new) {
30583cca8ef5SHugues Fruchet 		ret = ov5640_set_autogain(sensor, auto_gain);
305919a81c14SSteve Longerbeam 		if (ret)
306019a81c14SSteve Longerbeam 			return ret;
306119a81c14SSteve Longerbeam 	}
306219a81c14SSteve Longerbeam 
30633cca8ef5SHugues Fruchet 	if (!auto_gain && ctrls->gain->is_new)
30643cca8ef5SHugues Fruchet 		ret = ov5640_set_gain(sensor, ctrls->gain->val);
306519a81c14SSteve Longerbeam 
306619a81c14SSteve Longerbeam 	return ret;
306719a81c14SSteve Longerbeam }
306819a81c14SSteve Longerbeam 
30699f6d7bacSChen-Yu Tsai static const char * const test_pattern_menu[] = {
30709f6d7bacSChen-Yu Tsai 	"Disabled",
30719f6d7bacSChen-Yu Tsai 	"Color bars",
3072bddc5cdfSChen-Yu Tsai 	"Color bars w/ rolling bar",
3073bddc5cdfSChen-Yu Tsai 	"Color squares",
3074bddc5cdfSChen-Yu Tsai 	"Color squares w/ rolling bar",
30759f6d7bacSChen-Yu Tsai };
30769f6d7bacSChen-Yu Tsai 
3077a0c29afbSChen-Yu Tsai #define OV5640_TEST_ENABLE		BIT(7)
3078a0c29afbSChen-Yu Tsai #define OV5640_TEST_ROLLING		BIT(6)	/* rolling horizontal bar */
3079a0c29afbSChen-Yu Tsai #define OV5640_TEST_TRANSPARENT		BIT(5)
3080a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE_BW		BIT(4)	/* black & white squares */
3081a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_STANDARD	(0 << 2)
3082a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_1	(1 << 2)
3083a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_HOR_CHANGE	(2 << 2)
3084a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_2	(3 << 2)
3085a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR			(0 << 0)
3086a0c29afbSChen-Yu Tsai #define OV5640_TEST_RANDOM		(1 << 0)
3087a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE		(2 << 0)
3088a0c29afbSChen-Yu Tsai #define OV5640_TEST_BLACK		(3 << 0)
3089a0c29afbSChen-Yu Tsai 
3090a0c29afbSChen-Yu Tsai static const u8 test_pattern_val[] = {
3091a0c29afbSChen-Yu Tsai 	0,
30922aff1fc3SChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_BAR_VERT_CHANGE_1 |
3093a0c29afbSChen-Yu Tsai 		OV5640_TEST_BAR,
3094bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_ROLLING |
3095bddc5cdfSChen-Yu Tsai 		OV5640_TEST_BAR_VERT_CHANGE_1 | OV5640_TEST_BAR,
3096bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_SQUARE,
3097bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_ROLLING | OV5640_TEST_SQUARE,
3098a0c29afbSChen-Yu Tsai };
3099a0c29afbSChen-Yu Tsai 
310019a81c14SSteve Longerbeam static int ov5640_set_ctrl_test_pattern(struct ov5640_dev *sensor, int value)
310119a81c14SSteve Longerbeam {
3102a0c29afbSChen-Yu Tsai 	return ov5640_write_reg(sensor, OV5640_REG_PRE_ISP_TEST_SET1,
3103a0c29afbSChen-Yu Tsai 				test_pattern_val[value]);
310419a81c14SSteve Longerbeam }
310519a81c14SSteve Longerbeam 
31061068fecaSMylène Josserand static int ov5640_set_ctrl_light_freq(struct ov5640_dev *sensor, int value)
31071068fecaSMylène Josserand {
31081068fecaSMylène Josserand 	int ret;
31091068fecaSMylène Josserand 
31101068fecaSMylène Josserand 	ret = ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL01, BIT(7),
31111068fecaSMylène Josserand 			     (value == V4L2_CID_POWER_LINE_FREQUENCY_AUTO) ?
31121068fecaSMylène Josserand 			     0 : BIT(7));
31131068fecaSMylène Josserand 	if (ret)
31141068fecaSMylène Josserand 		return ret;
31151068fecaSMylène Josserand 
31161068fecaSMylène Josserand 	return ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL00, BIT(2),
31171068fecaSMylène Josserand 			      (value == V4L2_CID_POWER_LINE_FREQUENCY_50HZ) ?
31181068fecaSMylène Josserand 			      BIT(2) : 0);
31191068fecaSMylène Josserand }
31201068fecaSMylène Josserand 
3121ce85705aSHugues Fruchet static int ov5640_set_ctrl_hflip(struct ov5640_dev *sensor, int value)
3122ce85705aSHugues Fruchet {
3123ce85705aSHugues Fruchet 	/*
3124c3f3ba3eSHugues Fruchet 	 * If sensor is mounted upside down, mirror logic is inversed.
3125c3f3ba3eSHugues Fruchet 	 *
3126ce85705aSHugues Fruchet 	 * Sensor is a BSI (Back Side Illuminated) one,
3127ce85705aSHugues Fruchet 	 * so image captured is physically mirrored.
3128ce85705aSHugues Fruchet 	 * This is why mirror logic is inversed in
3129ce85705aSHugues Fruchet 	 * order to cancel this mirror effect.
3130ce85705aSHugues Fruchet 	 */
3131ce85705aSHugues Fruchet 
3132ce85705aSHugues Fruchet 	/*
3133ce85705aSHugues Fruchet 	 * TIMING TC REG21:
3134ce85705aSHugues Fruchet 	 * - [2]:	ISP mirror
3135ce85705aSHugues Fruchet 	 * - [1]:	Sensor mirror
3136ce85705aSHugues Fruchet 	 */
3137ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
3138ce85705aSHugues Fruchet 			      BIT(2) | BIT(1),
3139c3f3ba3eSHugues Fruchet 			      (!(value ^ sensor->upside_down)) ?
3140c3f3ba3eSHugues Fruchet 			      (BIT(2) | BIT(1)) : 0);
3141ce85705aSHugues Fruchet }
3142ce85705aSHugues Fruchet 
3143ce85705aSHugues Fruchet static int ov5640_set_ctrl_vflip(struct ov5640_dev *sensor, int value)
3144ce85705aSHugues Fruchet {
3145c3f3ba3eSHugues Fruchet 	/* If sensor is mounted upside down, flip logic is inversed */
3146c3f3ba3eSHugues Fruchet 
3147ce85705aSHugues Fruchet 	/*
3148ce85705aSHugues Fruchet 	 * TIMING TC REG20:
3149ce85705aSHugues Fruchet 	 * - [2]:	ISP vflip
3150ce85705aSHugues Fruchet 	 * - [1]:	Sensor vflip
3151ce85705aSHugues Fruchet 	 */
3152ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20,
3153ce85705aSHugues Fruchet 			      BIT(2) | BIT(1),
3154c3f3ba3eSHugues Fruchet 			      (value ^ sensor->upside_down) ?
3155c3f3ba3eSHugues Fruchet 			      (BIT(2) | BIT(1)) : 0);
3156ce85705aSHugues Fruchet }
3157ce85705aSHugues Fruchet 
3158*bce93b82SJacopo Mondi static int ov5640_set_ctrl_vblank(struct ov5640_dev *sensor, int value)
3159*bce93b82SJacopo Mondi {
3160*bce93b82SJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
3161*bce93b82SJacopo Mondi 
3162*bce93b82SJacopo Mondi 	/* Update the VTOT timing register value. */
3163*bce93b82SJacopo Mondi 	return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS,
3164*bce93b82SJacopo Mondi 				  mode->height + value);
3165*bce93b82SJacopo Mondi }
3166*bce93b82SJacopo Mondi 
316719a81c14SSteve Longerbeam static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
316819a81c14SSteve Longerbeam {
316919a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
317019a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
317119a81c14SSteve Longerbeam 	int val;
317219a81c14SSteve Longerbeam 
317319a81c14SSteve Longerbeam 	/* v4l2_ctrl_lock() locks our own mutex */
317419a81c14SSteve Longerbeam 
317519a81c14SSteve Longerbeam 	switch (ctrl->id) {
317619a81c14SSteve Longerbeam 	case V4L2_CID_AUTOGAIN:
317719a81c14SSteve Longerbeam 		val = ov5640_get_gain(sensor);
317819a81c14SSteve Longerbeam 		if (val < 0)
317919a81c14SSteve Longerbeam 			return val;
318019a81c14SSteve Longerbeam 		sensor->ctrls.gain->val = val;
318119a81c14SSteve Longerbeam 		break;
318219a81c14SSteve Longerbeam 	case V4L2_CID_EXPOSURE_AUTO:
318319a81c14SSteve Longerbeam 		val = ov5640_get_exposure(sensor);
318419a81c14SSteve Longerbeam 		if (val < 0)
318519a81c14SSteve Longerbeam 			return val;
318619a81c14SSteve Longerbeam 		sensor->ctrls.exposure->val = val;
318719a81c14SSteve Longerbeam 		break;
318819a81c14SSteve Longerbeam 	}
318919a81c14SSteve Longerbeam 
319019a81c14SSteve Longerbeam 	return 0;
319119a81c14SSteve Longerbeam }
319219a81c14SSteve Longerbeam 
319319a81c14SSteve Longerbeam static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl)
319419a81c14SSteve Longerbeam {
319519a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
319619a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
3197*bce93b82SJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
3198*bce93b82SJacopo Mondi 	const struct ov5640_timings *timings;
3199*bce93b82SJacopo Mondi 	unsigned int exp_max;
320019a81c14SSteve Longerbeam 	int ret;
320119a81c14SSteve Longerbeam 
320219a81c14SSteve Longerbeam 	/* v4l2_ctrl_lock() locks our own mutex */
320319a81c14SSteve Longerbeam 
3204*bce93b82SJacopo Mondi 	switch (ctrl->id) {
3205*bce93b82SJacopo Mondi 	case V4L2_CID_VBLANK:
3206*bce93b82SJacopo Mondi 		/* Update the exposure range to the newly programmed vblank. */
3207*bce93b82SJacopo Mondi 		timings = ov5640_timings(sensor, mode);
3208*bce93b82SJacopo Mondi 		exp_max = mode->height + ctrl->val - 4;
3209*bce93b82SJacopo Mondi 		__v4l2_ctrl_modify_range(sensor->ctrls.exposure,
3210*bce93b82SJacopo Mondi 					 sensor->ctrls.exposure->minimum,
3211*bce93b82SJacopo Mondi 					 exp_max, sensor->ctrls.exposure->step,
3212*bce93b82SJacopo Mondi 					 timings->vblank_def);
3213*bce93b82SJacopo Mondi 		break;
3214*bce93b82SJacopo Mondi 	}
3215*bce93b82SJacopo Mondi 
321619a81c14SSteve Longerbeam 	/*
321719a81c14SSteve Longerbeam 	 * If the device is not powered up by the host driver do
321819a81c14SSteve Longerbeam 	 * not apply any controls to H/W at this time. Instead
321919a81c14SSteve Longerbeam 	 * the controls will be restored right after power-up.
322019a81c14SSteve Longerbeam 	 */
322119a81c14SSteve Longerbeam 	if (sensor->power_count == 0)
322219a81c14SSteve Longerbeam 		return 0;
322319a81c14SSteve Longerbeam 
322419a81c14SSteve Longerbeam 	switch (ctrl->id) {
322519a81c14SSteve Longerbeam 	case V4L2_CID_AUTOGAIN:
322619a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_gain(sensor, ctrl->val);
322719a81c14SSteve Longerbeam 		break;
322819a81c14SSteve Longerbeam 	case V4L2_CID_EXPOSURE_AUTO:
322919a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_exposure(sensor, ctrl->val);
323019a81c14SSteve Longerbeam 		break;
323119a81c14SSteve Longerbeam 	case V4L2_CID_AUTO_WHITE_BALANCE:
323219a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_white_balance(sensor, ctrl->val);
323319a81c14SSteve Longerbeam 		break;
323419a81c14SSteve Longerbeam 	case V4L2_CID_HUE:
323519a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_hue(sensor, ctrl->val);
323619a81c14SSteve Longerbeam 		break;
323719a81c14SSteve Longerbeam 	case V4L2_CID_CONTRAST:
323819a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_contrast(sensor, ctrl->val);
323919a81c14SSteve Longerbeam 		break;
324019a81c14SSteve Longerbeam 	case V4L2_CID_SATURATION:
324119a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_saturation(sensor, ctrl->val);
324219a81c14SSteve Longerbeam 		break;
324319a81c14SSteve Longerbeam 	case V4L2_CID_TEST_PATTERN:
324419a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_test_pattern(sensor, ctrl->val);
324519a81c14SSteve Longerbeam 		break;
32461068fecaSMylène Josserand 	case V4L2_CID_POWER_LINE_FREQUENCY:
32471068fecaSMylène Josserand 		ret = ov5640_set_ctrl_light_freq(sensor, ctrl->val);
32481068fecaSMylène Josserand 		break;
3249ce85705aSHugues Fruchet 	case V4L2_CID_HFLIP:
3250ce85705aSHugues Fruchet 		ret = ov5640_set_ctrl_hflip(sensor, ctrl->val);
3251ce85705aSHugues Fruchet 		break;
3252ce85705aSHugues Fruchet 	case V4L2_CID_VFLIP:
3253ce85705aSHugues Fruchet 		ret = ov5640_set_ctrl_vflip(sensor, ctrl->val);
3254ce85705aSHugues Fruchet 		break;
3255*bce93b82SJacopo Mondi 	case V4L2_CID_VBLANK:
3256*bce93b82SJacopo Mondi 		ret = ov5640_set_ctrl_vblank(sensor, ctrl->val);
3257*bce93b82SJacopo Mondi 		break;
325819a81c14SSteve Longerbeam 	default:
325919a81c14SSteve Longerbeam 		ret = -EINVAL;
326019a81c14SSteve Longerbeam 		break;
326119a81c14SSteve Longerbeam 	}
326219a81c14SSteve Longerbeam 
326319a81c14SSteve Longerbeam 	return ret;
326419a81c14SSteve Longerbeam }
326519a81c14SSteve Longerbeam 
326619a81c14SSteve Longerbeam static const struct v4l2_ctrl_ops ov5640_ctrl_ops = {
326719a81c14SSteve Longerbeam 	.g_volatile_ctrl = ov5640_g_volatile_ctrl,
326819a81c14SSteve Longerbeam 	.s_ctrl = ov5640_s_ctrl,
326919a81c14SSteve Longerbeam };
327019a81c14SSteve Longerbeam 
327119a81c14SSteve Longerbeam static int ov5640_init_controls(struct ov5640_dev *sensor)
327219a81c14SSteve Longerbeam {
327322845bf2SJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
327419a81c14SSteve Longerbeam 	const struct v4l2_ctrl_ops *ops = &ov5640_ctrl_ops;
327519a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
327619a81c14SSteve Longerbeam 	struct v4l2_ctrl_handler *hdl = &ctrls->handler;
327732979f67SJacopo Mondi 	const struct ov5640_timings *timings;
3278*bce93b82SJacopo Mondi 	unsigned int max_vblank;
327932979f67SJacopo Mondi 	unsigned int hblank;
328019a81c14SSteve Longerbeam 	int ret;
328119a81c14SSteve Longerbeam 
328219a81c14SSteve Longerbeam 	v4l2_ctrl_handler_init(hdl, 32);
328319a81c14SSteve Longerbeam 
328419a81c14SSteve Longerbeam 	/* we can use our own mutex for the ctrl lock */
328519a81c14SSteve Longerbeam 	hdl->lock = &sensor->lock;
328619a81c14SSteve Longerbeam 
3287cc196e48SBenoit Parrot 	/* Clock related controls */
3288cc196e48SBenoit Parrot 	ctrls->pixel_rate = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE,
328922845bf2SJacopo Mondi 			      ov5640_pixel_rates[OV5640_NUM_PIXEL_RATES - 1],
329022845bf2SJacopo Mondi 			      ov5640_pixel_rates[0], 1,
329122845bf2SJacopo Mondi 			      ov5640_pixel_rates[mode->pixel_rate]);
3292cc196e48SBenoit Parrot 
32937a3b8d4bSJacopo Mondi 	ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops,
32947a3b8d4bSJacopo Mondi 					V4L2_CID_LINK_FREQ,
32957a3b8d4bSJacopo Mondi 					ARRAY_SIZE(ov5640_csi2_link_freqs) - 1,
32967a3b8d4bSJacopo Mondi 					OV5640_DEFAULT_LINK_FREQ,
32977a3b8d4bSJacopo Mondi 					ov5640_csi2_link_freqs);
32987a3b8d4bSJacopo Mondi 
329932979f67SJacopo Mondi 	timings = ov5640_timings(sensor, mode);
330032979f67SJacopo Mondi 	hblank = timings->htot - mode->width;
330132979f67SJacopo Mondi 	ctrls->hblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HBLANK, hblank,
330232979f67SJacopo Mondi 					  hblank, 1, hblank);
330332979f67SJacopo Mondi 
3304*bce93b82SJacopo Mondi 	max_vblank = OV5640_MAX_VTS - mode->height;
3305*bce93b82SJacopo Mondi 	ctrls->vblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VBLANK,
3306*bce93b82SJacopo Mondi 					  OV5640_MIN_VBLANK, max_vblank,
3307*bce93b82SJacopo Mondi 					  1, timings->vblank_def);
3308*bce93b82SJacopo Mondi 
330919a81c14SSteve Longerbeam 	/* Auto/manual white balance */
331019a81c14SSteve Longerbeam 	ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops,
331119a81c14SSteve Longerbeam 					   V4L2_CID_AUTO_WHITE_BALANCE,
331219a81c14SSteve Longerbeam 					   0, 1, 1, 1);
331319a81c14SSteve Longerbeam 	ctrls->blue_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BLUE_BALANCE,
331419a81c14SSteve Longerbeam 						0, 4095, 1, 0);
331519a81c14SSteve Longerbeam 	ctrls->red_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_RED_BALANCE,
331619a81c14SSteve Longerbeam 					       0, 4095, 1, 0);
331719a81c14SSteve Longerbeam 	/* Auto/manual exposure */
331819a81c14SSteve Longerbeam 	ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops,
331919a81c14SSteve Longerbeam 						 V4L2_CID_EXPOSURE_AUTO,
332019a81c14SSteve Longerbeam 						 V4L2_EXPOSURE_MANUAL, 0,
332119a81c14SSteve Longerbeam 						 V4L2_EXPOSURE_AUTO);
332219a81c14SSteve Longerbeam 	ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
332319a81c14SSteve Longerbeam 					    0, 65535, 1, 0);
332419a81c14SSteve Longerbeam 	/* Auto/manual gain */
332519a81c14SSteve Longerbeam 	ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN,
332619a81c14SSteve Longerbeam 					     0, 1, 1, 1);
332719a81c14SSteve Longerbeam 	ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN,
332819a81c14SSteve Longerbeam 					0, 1023, 1, 0);
332919a81c14SSteve Longerbeam 
333019a81c14SSteve Longerbeam 	ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION,
333119a81c14SSteve Longerbeam 					      0, 255, 1, 64);
333219a81c14SSteve Longerbeam 	ctrls->hue = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HUE,
333319a81c14SSteve Longerbeam 				       0, 359, 1, 0);
333419a81c14SSteve Longerbeam 	ctrls->contrast = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST,
333519a81c14SSteve Longerbeam 					    0, 255, 1, 0);
333619a81c14SSteve Longerbeam 	ctrls->test_pattern =
333719a81c14SSteve Longerbeam 		v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN,
333819a81c14SSteve Longerbeam 					     ARRAY_SIZE(test_pattern_menu) - 1,
333919a81c14SSteve Longerbeam 					     0, 0, test_pattern_menu);
3340ce85705aSHugues Fruchet 	ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP,
3341ce85705aSHugues Fruchet 					 0, 1, 1, 0);
3342ce85705aSHugues Fruchet 	ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP,
3343ce85705aSHugues Fruchet 					 0, 1, 1, 0);
334419a81c14SSteve Longerbeam 
33451068fecaSMylène Josserand 	ctrls->light_freq =
33461068fecaSMylène Josserand 		v4l2_ctrl_new_std_menu(hdl, ops,
33471068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY,
33481068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
33491068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
33501068fecaSMylène Josserand 
335119a81c14SSteve Longerbeam 	if (hdl->error) {
335219a81c14SSteve Longerbeam 		ret = hdl->error;
335319a81c14SSteve Longerbeam 		goto free_ctrls;
335419a81c14SSteve Longerbeam 	}
335519a81c14SSteve Longerbeam 
3356cc196e48SBenoit Parrot 	ctrls->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY;
33577a3b8d4bSJacopo Mondi 	ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
335832979f67SJacopo Mondi 	ctrls->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
335919a81c14SSteve Longerbeam 	ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE;
336019a81c14SSteve Longerbeam 	ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE;
336119a81c14SSteve Longerbeam 
336219a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false);
336319a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(2, &ctrls->auto_gain, 0, true);
336419a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(2, &ctrls->auto_exp, 1, true);
336519a81c14SSteve Longerbeam 
336619a81c14SSteve Longerbeam 	sensor->sd.ctrl_handler = hdl;
336719a81c14SSteve Longerbeam 	return 0;
336819a81c14SSteve Longerbeam 
336919a81c14SSteve Longerbeam free_ctrls:
337019a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(hdl);
337119a81c14SSteve Longerbeam 	return ret;
337219a81c14SSteve Longerbeam }
337319a81c14SSteve Longerbeam 
337419a81c14SSteve Longerbeam static int ov5640_enum_frame_size(struct v4l2_subdev *sd,
33750d346d2aSTomi Valkeinen 				  struct v4l2_subdev_state *sd_state,
337619a81c14SSteve Longerbeam 				  struct v4l2_subdev_frame_size_enum *fse)
337719a81c14SSteve Longerbeam {
337819a81c14SSteve Longerbeam 	if (fse->pad != 0)
337919a81c14SSteve Longerbeam 		return -EINVAL;
338019a81c14SSteve Longerbeam 	if (fse->index >= OV5640_NUM_MODES)
338119a81c14SSteve Longerbeam 		return -EINVAL;
338219a81c14SSteve Longerbeam 
33835113d5b3SJacopo Mondi 	fse->min_width = ov5640_mode_data[fse->index].width;
338441d8d7f5SHugues Fruchet 	fse->max_width = fse->min_width;
33855113d5b3SJacopo Mondi 	fse->min_height = ov5640_mode_data[fse->index].height;
338641d8d7f5SHugues Fruchet 	fse->max_height = fse->min_height;
338719a81c14SSteve Longerbeam 
338819a81c14SSteve Longerbeam 	return 0;
338919a81c14SSteve Longerbeam }
339019a81c14SSteve Longerbeam 
339119a81c14SSteve Longerbeam static int ov5640_enum_frame_interval(
339219a81c14SSteve Longerbeam 	struct v4l2_subdev *sd,
33930d346d2aSTomi Valkeinen 	struct v4l2_subdev_state *sd_state,
339419a81c14SSteve Longerbeam 	struct v4l2_subdev_frame_interval_enum *fie)
339519a81c14SSteve Longerbeam {
339619a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
339719a81c14SSteve Longerbeam 	struct v4l2_fract tpf;
339819a81c14SSteve Longerbeam 	int ret;
339919a81c14SSteve Longerbeam 
340019a81c14SSteve Longerbeam 	if (fie->pad != 0)
340119a81c14SSteve Longerbeam 		return -EINVAL;
340219a81c14SSteve Longerbeam 	if (fie->index >= OV5640_NUM_FRAMERATES)
340319a81c14SSteve Longerbeam 		return -EINVAL;
340419a81c14SSteve Longerbeam 
340519a81c14SSteve Longerbeam 	tpf.numerator = 1;
340619a81c14SSteve Longerbeam 	tpf.denominator = ov5640_framerates[fie->index];
340719a81c14SSteve Longerbeam 
340819a81c14SSteve Longerbeam 	ret = ov5640_try_frame_interval(sensor, &tpf,
340919a81c14SSteve Longerbeam 					fie->width, fie->height);
341019a81c14SSteve Longerbeam 	if (ret < 0)
341119a81c14SSteve Longerbeam 		return -EINVAL;
341219a81c14SSteve Longerbeam 
341319a81c14SSteve Longerbeam 	fie->interval = tpf;
341419a81c14SSteve Longerbeam 	return 0;
341519a81c14SSteve Longerbeam }
341619a81c14SSteve Longerbeam 
341719a81c14SSteve Longerbeam static int ov5640_g_frame_interval(struct v4l2_subdev *sd,
341819a81c14SSteve Longerbeam 				   struct v4l2_subdev_frame_interval *fi)
341919a81c14SSteve Longerbeam {
342019a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
342119a81c14SSteve Longerbeam 
342219a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
342319a81c14SSteve Longerbeam 	fi->interval = sensor->frame_interval;
342419a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
342519a81c14SSteve Longerbeam 
342619a81c14SSteve Longerbeam 	return 0;
342719a81c14SSteve Longerbeam }
342819a81c14SSteve Longerbeam 
342919a81c14SSteve Longerbeam static int ov5640_s_frame_interval(struct v4l2_subdev *sd,
343019a81c14SSteve Longerbeam 				   struct v4l2_subdev_frame_interval *fi)
343119a81c14SSteve Longerbeam {
343219a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
343319a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
343419a81c14SSteve Longerbeam 	int frame_rate, ret = 0;
343519a81c14SSteve Longerbeam 
343619a81c14SSteve Longerbeam 	if (fi->pad != 0)
343719a81c14SSteve Longerbeam 		return -EINVAL;
343819a81c14SSteve Longerbeam 
343919a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
344019a81c14SSteve Longerbeam 
344119a81c14SSteve Longerbeam 	if (sensor->streaming) {
344219a81c14SSteve Longerbeam 		ret = -EBUSY;
344319a81c14SSteve Longerbeam 		goto out;
344419a81c14SSteve Longerbeam 	}
344519a81c14SSteve Longerbeam 
344619a81c14SSteve Longerbeam 	mode = sensor->current_mode;
344719a81c14SSteve Longerbeam 
344819a81c14SSteve Longerbeam 	frame_rate = ov5640_try_frame_interval(sensor, &fi->interval,
34495113d5b3SJacopo Mondi 					       mode->width,
34505113d5b3SJacopo Mondi 					       mode->height);
3451e823fb16SMaxime Ripard 	if (frame_rate < 0) {
3452e823fb16SMaxime Ripard 		/* Always return a valid frame interval value */
3453e823fb16SMaxime Ripard 		fi->interval = sensor->frame_interval;
3454e823fb16SMaxime Ripard 		goto out;
3455e823fb16SMaxime Ripard 	}
345619a81c14SSteve Longerbeam 
34575113d5b3SJacopo Mondi 	mode = ov5640_find_mode(sensor, frame_rate, mode->width,
34585113d5b3SJacopo Mondi 				mode->height, true);
34593c4a7372SHugues Fruchet 	if (!mode) {
34603c4a7372SHugues Fruchet 		ret = -EINVAL;
34613c4a7372SHugues Fruchet 		goto out;
34623c4a7372SHugues Fruchet 	}
34633c4a7372SHugues Fruchet 
34640929983eSHugues Fruchet 	if (mode != sensor->current_mode ||
34650929983eSHugues Fruchet 	    frame_rate != sensor->current_fr) {
34660929983eSHugues Fruchet 		sensor->current_fr = frame_rate;
34670929983eSHugues Fruchet 		sensor->frame_interval = fi->interval;
34683c4a7372SHugues Fruchet 		sensor->current_mode = mode;
346919a81c14SSteve Longerbeam 		sensor->pending_mode_change = true;
3470cc196e48SBenoit Parrot 
3471cc196e48SBenoit Parrot 		__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate,
3472cc196e48SBenoit Parrot 					 ov5640_calc_pixel_rate(sensor));
34736949d864SHugues Fruchet 	}
347419a81c14SSteve Longerbeam out:
347519a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
347619a81c14SSteve Longerbeam 	return ret;
347719a81c14SSteve Longerbeam }
347819a81c14SSteve Longerbeam 
347919a81c14SSteve Longerbeam static int ov5640_enum_mbus_code(struct v4l2_subdev *sd,
34800d346d2aSTomi Valkeinen 				 struct v4l2_subdev_state *sd_state,
348119a81c14SSteve Longerbeam 				 struct v4l2_subdev_mbus_code_enum *code)
348219a81c14SSteve Longerbeam {
348319a81c14SSteve Longerbeam 	if (code->pad != 0)
348419a81c14SSteve Longerbeam 		return -EINVAL;
3485e3ee691dSHugues Fruchet 	if (code->index >= ARRAY_SIZE(ov5640_formats))
348619a81c14SSteve Longerbeam 		return -EINVAL;
348719a81c14SSteve Longerbeam 
3488e3ee691dSHugues Fruchet 	code->code = ov5640_formats[code->index].code;
348919a81c14SSteve Longerbeam 	return 0;
349019a81c14SSteve Longerbeam }
349119a81c14SSteve Longerbeam 
349219a81c14SSteve Longerbeam static int ov5640_s_stream(struct v4l2_subdev *sd, int enable)
349319a81c14SSteve Longerbeam {
349419a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
349519a81c14SSteve Longerbeam 	int ret = 0;
349619a81c14SSteve Longerbeam 
349719a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
349819a81c14SSteve Longerbeam 
349919a81c14SSteve Longerbeam 	if (sensor->streaming == !enable) {
350019a81c14SSteve Longerbeam 		if (enable && sensor->pending_mode_change) {
3501985cdcb0SHugues Fruchet 			ret = ov5640_set_mode(sensor);
350219a81c14SSteve Longerbeam 			if (ret)
350319a81c14SSteve Longerbeam 				goto out;
3504fb98e29fSHugues Fruchet 		}
3505e3ee691dSHugues Fruchet 
3506fb98e29fSHugues Fruchet 		if (enable && sensor->pending_fmt_change) {
3507e3ee691dSHugues Fruchet 			ret = ov5640_set_framefmt(sensor, &sensor->fmt);
3508e3ee691dSHugues Fruchet 			if (ret)
3509e3ee691dSHugues Fruchet 				goto out;
3510fb98e29fSHugues Fruchet 			sensor->pending_fmt_change = false;
351119a81c14SSteve Longerbeam 		}
351219a81c14SSteve Longerbeam 
35138e823f5cSJacopo Mondi 		if (ov5640_is_csi2(sensor))
3514f22996dbSHugues Fruchet 			ret = ov5640_set_stream_mipi(sensor, enable);
3515f22996dbSHugues Fruchet 		else
3516f22996dbSHugues Fruchet 			ret = ov5640_set_stream_dvp(sensor, enable);
3517f22996dbSHugues Fruchet 
351819a81c14SSteve Longerbeam 		if (!ret)
351919a81c14SSteve Longerbeam 			sensor->streaming = enable;
352019a81c14SSteve Longerbeam 	}
352119a81c14SSteve Longerbeam out:
352219a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
352319a81c14SSteve Longerbeam 	return ret;
352419a81c14SSteve Longerbeam }
352519a81c14SSteve Longerbeam 
352619a81c14SSteve Longerbeam static const struct v4l2_subdev_core_ops ov5640_core_ops = {
352719a81c14SSteve Longerbeam 	.s_power = ov5640_s_power,
35282d18fbc5SAkinobu Mita 	.log_status = v4l2_ctrl_subdev_log_status,
35292d18fbc5SAkinobu Mita 	.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
35302d18fbc5SAkinobu Mita 	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
353119a81c14SSteve Longerbeam };
353219a81c14SSteve Longerbeam 
353319a81c14SSteve Longerbeam static const struct v4l2_subdev_video_ops ov5640_video_ops = {
353419a81c14SSteve Longerbeam 	.g_frame_interval = ov5640_g_frame_interval,
353519a81c14SSteve Longerbeam 	.s_frame_interval = ov5640_s_frame_interval,
353619a81c14SSteve Longerbeam 	.s_stream = ov5640_s_stream,
353719a81c14SSteve Longerbeam };
353819a81c14SSteve Longerbeam 
353919a81c14SSteve Longerbeam static const struct v4l2_subdev_pad_ops ov5640_pad_ops = {
354019a81c14SSteve Longerbeam 	.enum_mbus_code = ov5640_enum_mbus_code,
354119a81c14SSteve Longerbeam 	.get_fmt = ov5640_get_fmt,
354219a81c14SSteve Longerbeam 	.set_fmt = ov5640_set_fmt,
354319a81c14SSteve Longerbeam 	.enum_frame_size = ov5640_enum_frame_size,
354419a81c14SSteve Longerbeam 	.enum_frame_interval = ov5640_enum_frame_interval,
354519a81c14SSteve Longerbeam };
354619a81c14SSteve Longerbeam 
354719a81c14SSteve Longerbeam static const struct v4l2_subdev_ops ov5640_subdev_ops = {
354819a81c14SSteve Longerbeam 	.core = &ov5640_core_ops,
354919a81c14SSteve Longerbeam 	.video = &ov5640_video_ops,
355019a81c14SSteve Longerbeam 	.pad = &ov5640_pad_ops,
355119a81c14SSteve Longerbeam };
355219a81c14SSteve Longerbeam 
355319a81c14SSteve Longerbeam static int ov5640_get_regulators(struct ov5640_dev *sensor)
355419a81c14SSteve Longerbeam {
355519a81c14SSteve Longerbeam 	int i;
355619a81c14SSteve Longerbeam 
355719a81c14SSteve Longerbeam 	for (i = 0; i < OV5640_NUM_SUPPLIES; i++)
355819a81c14SSteve Longerbeam 		sensor->supplies[i].supply = ov5640_supply_name[i];
355919a81c14SSteve Longerbeam 
356019a81c14SSteve Longerbeam 	return devm_regulator_bulk_get(&sensor->i2c_client->dev,
356119a81c14SSteve Longerbeam 				       OV5640_NUM_SUPPLIES,
356219a81c14SSteve Longerbeam 				       sensor->supplies);
356319a81c14SSteve Longerbeam }
356419a81c14SSteve Longerbeam 
35650f7acb52SHugues Fruchet static int ov5640_check_chip_id(struct ov5640_dev *sensor)
35660f7acb52SHugues Fruchet {
35670f7acb52SHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
35680f7acb52SHugues Fruchet 	int ret = 0;
35690f7acb52SHugues Fruchet 	u16 chip_id;
35700f7acb52SHugues Fruchet 
35710f7acb52SHugues Fruchet 	ret = ov5640_set_power_on(sensor);
35720f7acb52SHugues Fruchet 	if (ret)
35730f7acb52SHugues Fruchet 		return ret;
35740f7acb52SHugues Fruchet 
35750f7acb52SHugues Fruchet 	ret = ov5640_read_reg16(sensor, OV5640_REG_CHIP_ID, &chip_id);
35760f7acb52SHugues Fruchet 	if (ret) {
35770f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to read chip identifier\n",
35780f7acb52SHugues Fruchet 			__func__);
35790f7acb52SHugues Fruchet 		goto power_off;
35800f7acb52SHugues Fruchet 	}
35810f7acb52SHugues Fruchet 
35820f7acb52SHugues Fruchet 	if (chip_id != 0x5640) {
35830f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: wrong chip identifier, expected 0x5640, got 0x%x\n",
35840f7acb52SHugues Fruchet 			__func__, chip_id);
35850f7acb52SHugues Fruchet 		ret = -ENXIO;
35860f7acb52SHugues Fruchet 	}
35870f7acb52SHugues Fruchet 
35880f7acb52SHugues Fruchet power_off:
35890f7acb52SHugues Fruchet 	ov5640_set_power_off(sensor);
35900f7acb52SHugues Fruchet 	return ret;
35910f7acb52SHugues Fruchet }
35920f7acb52SHugues Fruchet 
3593e6714993SKieran Bingham static int ov5640_probe(struct i2c_client *client)
359419a81c14SSteve Longerbeam {
359519a81c14SSteve Longerbeam 	struct device *dev = &client->dev;
359619a81c14SSteve Longerbeam 	struct fwnode_handle *endpoint;
359719a81c14SSteve Longerbeam 	struct ov5640_dev *sensor;
3598e6441fdeSHugues Fruchet 	struct v4l2_mbus_framefmt *fmt;
3599c3f3ba3eSHugues Fruchet 	u32 rotation;
360019a81c14SSteve Longerbeam 	int ret;
360119a81c14SSteve Longerbeam 
360219a81c14SSteve Longerbeam 	sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
360319a81c14SSteve Longerbeam 	if (!sensor)
360419a81c14SSteve Longerbeam 		return -ENOMEM;
360519a81c14SSteve Longerbeam 
360619a81c14SSteve Longerbeam 	sensor->i2c_client = client;
3607fb98e29fSHugues Fruchet 
3608fb98e29fSHugues Fruchet 	/*
3609fb98e29fSHugues Fruchet 	 * default init sequence initialize sensor to
3610fb98e29fSHugues Fruchet 	 * YUV422 UYVY VGA@30fps
3611fb98e29fSHugues Fruchet 	 */
3612e6441fdeSHugues Fruchet 	fmt = &sensor->fmt;
3613fb98e29fSHugues Fruchet 	fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
3614fb98e29fSHugues Fruchet 	fmt->colorspace = V4L2_COLORSPACE_SRGB;
3615e6441fdeSHugues Fruchet 	fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
3616e6441fdeSHugues Fruchet 	fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
3617e6441fdeSHugues Fruchet 	fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
3618e6441fdeSHugues Fruchet 	fmt->width = 640;
3619e6441fdeSHugues Fruchet 	fmt->height = 480;
3620e6441fdeSHugues Fruchet 	fmt->field = V4L2_FIELD_NONE;
362119a81c14SSteve Longerbeam 	sensor->frame_interval.numerator = 1;
362219a81c14SSteve Longerbeam 	sensor->frame_interval.denominator = ov5640_framerates[OV5640_30_FPS];
362319a81c14SSteve Longerbeam 	sensor->current_fr = OV5640_30_FPS;
362419a81c14SSteve Longerbeam 	sensor->current_mode =
3625086c25f8SMaxime Ripard 		&ov5640_mode_data[OV5640_MODE_VGA_640_480];
3626985cdcb0SHugues Fruchet 	sensor->last_mode = sensor->current_mode;
36273c28588fSJacopo Mondi 	sensor->current_link_freq = OV5640_DEFAULT_LINK_FREQ;
362819a81c14SSteve Longerbeam 
362919a81c14SSteve Longerbeam 	sensor->ae_target = 52;
363019a81c14SSteve Longerbeam 
3631c3f3ba3eSHugues Fruchet 	/* optional indication of physical rotation of sensor */
3632c3f3ba3eSHugues Fruchet 	ret = fwnode_property_read_u32(dev_fwnode(&client->dev), "rotation",
3633c3f3ba3eSHugues Fruchet 				       &rotation);
3634c3f3ba3eSHugues Fruchet 	if (!ret) {
3635c3f3ba3eSHugues Fruchet 		switch (rotation) {
3636c3f3ba3eSHugues Fruchet 		case 180:
3637c3f3ba3eSHugues Fruchet 			sensor->upside_down = true;
36381771e9fbSGustavo A. R. Silva 			fallthrough;
3639c3f3ba3eSHugues Fruchet 		case 0:
3640c3f3ba3eSHugues Fruchet 			break;
3641c3f3ba3eSHugues Fruchet 		default:
3642c3f3ba3eSHugues Fruchet 			dev_warn(dev, "%u degrees rotation is not supported, ignoring...\n",
3643c3f3ba3eSHugues Fruchet 				 rotation);
3644c3f3ba3eSHugues Fruchet 		}
3645c3f3ba3eSHugues Fruchet 	}
3646c3f3ba3eSHugues Fruchet 
3647ce96bcf5SSakari Ailus 	endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev),
3648ce96bcf5SSakari Ailus 						  NULL);
364919a81c14SSteve Longerbeam 	if (!endpoint) {
365019a81c14SSteve Longerbeam 		dev_err(dev, "endpoint node not found\n");
365119a81c14SSteve Longerbeam 		return -EINVAL;
365219a81c14SSteve Longerbeam 	}
365319a81c14SSteve Longerbeam 
365419a81c14SSteve Longerbeam 	ret = v4l2_fwnode_endpoint_parse(endpoint, &sensor->ep);
365519a81c14SSteve Longerbeam 	fwnode_handle_put(endpoint);
365619a81c14SSteve Longerbeam 	if (ret) {
365719a81c14SSteve Longerbeam 		dev_err(dev, "Could not parse endpoint\n");
365819a81c14SSteve Longerbeam 		return ret;
365919a81c14SSteve Longerbeam 	}
366019a81c14SSteve Longerbeam 
36612c61e48dSLad Prabhakar 	if (sensor->ep.bus_type != V4L2_MBUS_PARALLEL &&
36622c61e48dSLad Prabhakar 	    sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY &&
36632c61e48dSLad Prabhakar 	    sensor->ep.bus_type != V4L2_MBUS_BT656) {
36642c61e48dSLad Prabhakar 		dev_err(dev, "Unsupported bus type %d\n", sensor->ep.bus_type);
36652c61e48dSLad Prabhakar 		return -EINVAL;
36662c61e48dSLad Prabhakar 	}
36672c61e48dSLad Prabhakar 
366819a81c14SSteve Longerbeam 	/* get system clock (xclk) */
366919a81c14SSteve Longerbeam 	sensor->xclk = devm_clk_get(dev, "xclk");
367019a81c14SSteve Longerbeam 	if (IS_ERR(sensor->xclk)) {
367119a81c14SSteve Longerbeam 		dev_err(dev, "failed to get xclk\n");
367219a81c14SSteve Longerbeam 		return PTR_ERR(sensor->xclk);
367319a81c14SSteve Longerbeam 	}
367419a81c14SSteve Longerbeam 
367519a81c14SSteve Longerbeam 	sensor->xclk_freq = clk_get_rate(sensor->xclk);
367619a81c14SSteve Longerbeam 	if (sensor->xclk_freq < OV5640_XCLK_MIN ||
367719a81c14SSteve Longerbeam 	    sensor->xclk_freq > OV5640_XCLK_MAX) {
367819a81c14SSteve Longerbeam 		dev_err(dev, "xclk frequency out of range: %d Hz\n",
367919a81c14SSteve Longerbeam 			sensor->xclk_freq);
368019a81c14SSteve Longerbeam 		return -EINVAL;
368119a81c14SSteve Longerbeam 	}
368219a81c14SSteve Longerbeam 
368319a81c14SSteve Longerbeam 	/* request optional power down pin */
368419a81c14SSteve Longerbeam 	sensor->pwdn_gpio = devm_gpiod_get_optional(dev, "powerdown",
368519a81c14SSteve Longerbeam 						    GPIOD_OUT_HIGH);
36868791a102SFabio Estevam 	if (IS_ERR(sensor->pwdn_gpio))
36878791a102SFabio Estevam 		return PTR_ERR(sensor->pwdn_gpio);
36888791a102SFabio Estevam 
368919a81c14SSteve Longerbeam 	/* request optional reset pin */
369019a81c14SSteve Longerbeam 	sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset",
369119a81c14SSteve Longerbeam 						     GPIOD_OUT_HIGH);
36928791a102SFabio Estevam 	if (IS_ERR(sensor->reset_gpio))
36938791a102SFabio Estevam 		return PTR_ERR(sensor->reset_gpio);
369419a81c14SSteve Longerbeam 
369519a81c14SSteve Longerbeam 	v4l2_i2c_subdev_init(&sensor->sd, client, &ov5640_subdev_ops);
369619a81c14SSteve Longerbeam 
36972d18fbc5SAkinobu Mita 	sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
36982d18fbc5SAkinobu Mita 			    V4L2_SUBDEV_FL_HAS_EVENTS;
369919a81c14SSteve Longerbeam 	sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
370019a81c14SSteve Longerbeam 	sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
370119a81c14SSteve Longerbeam 	ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
370219a81c14SSteve Longerbeam 	if (ret)
370319a81c14SSteve Longerbeam 		return ret;
370419a81c14SSteve Longerbeam 
370519a81c14SSteve Longerbeam 	ret = ov5640_get_regulators(sensor);
370619a81c14SSteve Longerbeam 	if (ret)
370719a81c14SSteve Longerbeam 		return ret;
370819a81c14SSteve Longerbeam 
370919a81c14SSteve Longerbeam 	mutex_init(&sensor->lock);
371019a81c14SSteve Longerbeam 
37110f7acb52SHugues Fruchet 	ret = ov5640_check_chip_id(sensor);
37120f7acb52SHugues Fruchet 	if (ret)
37130f7acb52SHugues Fruchet 		goto entity_cleanup;
37140f7acb52SHugues Fruchet 
371519a81c14SSteve Longerbeam 	ret = ov5640_init_controls(sensor);
371619a81c14SSteve Longerbeam 	if (ret)
371719a81c14SSteve Longerbeam 		goto entity_cleanup;
371819a81c14SSteve Longerbeam 
371915786f7bSSakari Ailus 	ret = v4l2_async_register_subdev_sensor(&sensor->sd);
372019a81c14SSteve Longerbeam 	if (ret)
372119a81c14SSteve Longerbeam 		goto free_ctrls;
372219a81c14SSteve Longerbeam 
372319a81c14SSteve Longerbeam 	return 0;
372419a81c14SSteve Longerbeam 
372519a81c14SSteve Longerbeam free_ctrls:
372619a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
372719a81c14SSteve Longerbeam entity_cleanup:
372819a81c14SSteve Longerbeam 	media_entity_cleanup(&sensor->sd.entity);
3729bfcba38dSTomi Valkeinen 	mutex_destroy(&sensor->lock);
373019a81c14SSteve Longerbeam 	return ret;
373119a81c14SSteve Longerbeam }
373219a81c14SSteve Longerbeam 
373319a81c14SSteve Longerbeam static int ov5640_remove(struct i2c_client *client)
373419a81c14SSteve Longerbeam {
373519a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
373619a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
373719a81c14SSteve Longerbeam 
373819a81c14SSteve Longerbeam 	v4l2_async_unregister_subdev(&sensor->sd);
373919a81c14SSteve Longerbeam 	media_entity_cleanup(&sensor->sd.entity);
374019a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
3741bfcba38dSTomi Valkeinen 	mutex_destroy(&sensor->lock);
374219a81c14SSteve Longerbeam 
374319a81c14SSteve Longerbeam 	return 0;
374419a81c14SSteve Longerbeam }
374519a81c14SSteve Longerbeam 
374619a81c14SSteve Longerbeam static const struct i2c_device_id ov5640_id[] = {
374719a81c14SSteve Longerbeam 	{"ov5640", 0},
374819a81c14SSteve Longerbeam 	{},
374919a81c14SSteve Longerbeam };
375019a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(i2c, ov5640_id);
375119a81c14SSteve Longerbeam 
375219a81c14SSteve Longerbeam static const struct of_device_id ov5640_dt_ids[] = {
375319a81c14SSteve Longerbeam 	{ .compatible = "ovti,ov5640" },
375419a81c14SSteve Longerbeam 	{ /* sentinel */ }
375519a81c14SSteve Longerbeam };
375619a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(of, ov5640_dt_ids);
375719a81c14SSteve Longerbeam 
375819a81c14SSteve Longerbeam static struct i2c_driver ov5640_i2c_driver = {
375919a81c14SSteve Longerbeam 	.driver = {
376019a81c14SSteve Longerbeam 		.name  = "ov5640",
376119a81c14SSteve Longerbeam 		.of_match_table	= ov5640_dt_ids,
376219a81c14SSteve Longerbeam 	},
376319a81c14SSteve Longerbeam 	.id_table = ov5640_id,
3764e6714993SKieran Bingham 	.probe_new = ov5640_probe,
376519a81c14SSteve Longerbeam 	.remove   = ov5640_remove,
376619a81c14SSteve Longerbeam };
376719a81c14SSteve Longerbeam 
376819a81c14SSteve Longerbeam module_i2c_driver(ov5640_i2c_driver);
376919a81c14SSteve Longerbeam 
377019a81c14SSteve Longerbeam MODULE_DESCRIPTION("OV5640 MIPI Camera Subdev Driver");
377119a81c14SSteve Longerbeam MODULE_LICENSE("GPL");
3772