xref: /openbmc/linux/drivers/media/i2c/ov5640.c (revision e4359019)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
219a81c14SSteve Longerbeam /*
319a81c14SSteve Longerbeam  * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
419a81c14SSteve Longerbeam  * Copyright (C) 2014-2017 Mentor Graphics Inc.
519a81c14SSteve Longerbeam  */
619a81c14SSteve Longerbeam 
719a81c14SSteve Longerbeam #include <linux/clk.h>
819a81c14SSteve Longerbeam #include <linux/clk-provider.h>
919a81c14SSteve Longerbeam #include <linux/clkdev.h>
1019a81c14SSteve Longerbeam #include <linux/ctype.h>
1119a81c14SSteve Longerbeam #include <linux/delay.h>
1219a81c14SSteve Longerbeam #include <linux/device.h>
1341d8d7f5SHugues Fruchet #include <linux/gpio/consumer.h>
1419a81c14SSteve Longerbeam #include <linux/i2c.h>
1519a81c14SSteve Longerbeam #include <linux/init.h>
1619a81c14SSteve Longerbeam #include <linux/module.h>
1719a81c14SSteve Longerbeam #include <linux/of_device.h>
1841d8d7f5SHugues Fruchet #include <linux/regulator/consumer.h>
1919a81c14SSteve Longerbeam #include <linux/slab.h>
2019a81c14SSteve Longerbeam #include <linux/types.h>
2119a81c14SSteve Longerbeam #include <media/v4l2-async.h>
2219a81c14SSteve Longerbeam #include <media/v4l2-ctrls.h>
2319a81c14SSteve Longerbeam #include <media/v4l2-device.h>
242d18fbc5SAkinobu Mita #include <media/v4l2-event.h>
2519a81c14SSteve Longerbeam #include <media/v4l2-fwnode.h>
2619a81c14SSteve Longerbeam #include <media/v4l2-subdev.h>
2719a81c14SSteve Longerbeam 
2819a81c14SSteve Longerbeam /* min/typical/max system clock (xclk) frequencies */
2919a81c14SSteve Longerbeam #define OV5640_XCLK_MIN  6000000
3041cb1c73SPhilipp Puschmann #define OV5640_XCLK_MAX 54000000
3119a81c14SSteve Longerbeam 
325113d5b3SJacopo Mondi #define OV5640_NATIVE_WIDTH		2624
335113d5b3SJacopo Mondi #define OV5640_NATIVE_HEIGHT		1964
345113d5b3SJacopo Mondi #define OV5640_PIXEL_ARRAY_TOP		14
355113d5b3SJacopo Mondi #define OV5640_PIXEL_ARRAY_LEFT		16
365113d5b3SJacopo Mondi #define OV5640_PIXEL_ARRAY_WIDTH	2592
375113d5b3SJacopo Mondi #define OV5640_PIXEL_ARRAY_HEIGHT	1944
385113d5b3SJacopo Mondi 
3919a81c14SSteve Longerbeam #define OV5640_DEFAULT_SLAVE_ID 0x3c
4019a81c14SSteve Longerbeam 
413c28588fSJacopo Mondi #define OV5640_LINK_RATE_MAX		490000000U
423c28588fSJacopo Mondi 
43d47c4126SHugues Fruchet #define OV5640_REG_SYS_RESET02		0x3002
44d47c4126SHugues Fruchet #define OV5640_REG_SYS_CLOCK_ENABLE02	0x3006
45f22996dbSHugues Fruchet #define OV5640_REG_SYS_CTRL0		0x3008
463b987d70SLad Prabhakar #define OV5640_REG_SYS_CTRL0_SW_PWDN	0x42
473b987d70SLad Prabhakar #define OV5640_REG_SYS_CTRL0_SW_PWUP	0x02
4819a81c14SSteve Longerbeam #define OV5640_REG_CHIP_ID		0x300a
49f22996dbSHugues Fruchet #define OV5640_REG_IO_MIPI_CTRL00	0x300e
50f22996dbSHugues Fruchet #define OV5640_REG_PAD_OUTPUT_ENABLE01	0x3017
51f22996dbSHugues Fruchet #define OV5640_REG_PAD_OUTPUT_ENABLE02	0x3018
5219a81c14SSteve Longerbeam #define OV5640_REG_PAD_OUTPUT00		0x3019
53f22996dbSHugues Fruchet #define OV5640_REG_SYSTEM_CONTROL1	0x302e
5419a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL0		0x3034
5519a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL1		0x3035
5619a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL2		0x3036
5719a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL3		0x3037
5819a81c14SSteve Longerbeam #define OV5640_REG_SLAVE_ID		0x3100
59f22996dbSHugues Fruchet #define OV5640_REG_SCCB_SYS_CTRL1	0x3103
6019a81c14SSteve Longerbeam #define OV5640_REG_SYS_ROOT_DIVIDER	0x3108
6119a81c14SSteve Longerbeam #define OV5640_REG_AWB_R_GAIN		0x3400
6219a81c14SSteve Longerbeam #define OV5640_REG_AWB_G_GAIN		0x3402
6319a81c14SSteve Longerbeam #define OV5640_REG_AWB_B_GAIN		0x3404
6419a81c14SSteve Longerbeam #define OV5640_REG_AWB_MANUAL_CTRL	0x3406
6519a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_HI	0x3500
6619a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_MED	0x3501
6719a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_LO	0x3502
6819a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_MANUAL	0x3503
6919a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_REAL_GAIN	0x350a
7019a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_VTS		0x350c
713145efcdSJacopo Mondi #define OV5640_REG_TIMING_HS		0x3800
723145efcdSJacopo Mondi #define OV5640_REG_TIMING_VS		0x3802
733145efcdSJacopo Mondi #define OV5640_REG_TIMING_HW		0x3804
743145efcdSJacopo Mondi #define OV5640_REG_TIMING_VH		0x3806
7586633417SMaxime Ripard #define OV5640_REG_TIMING_DVPHO		0x3808
7686633417SMaxime Ripard #define OV5640_REG_TIMING_DVPVO		0x380a
7719a81c14SSteve Longerbeam #define OV5640_REG_TIMING_HTS		0x380c
7819a81c14SSteve Longerbeam #define OV5640_REG_TIMING_VTS		0x380e
793145efcdSJacopo Mondi #define OV5640_REG_TIMING_HOFFS		0x3810
803145efcdSJacopo Mondi #define OV5640_REG_TIMING_VOFFS		0x3812
81ce85705aSHugues Fruchet #define OV5640_REG_TIMING_TC_REG20	0x3820
8219a81c14SSteve Longerbeam #define OV5640_REG_TIMING_TC_REG21	0x3821
8319a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL00		0x3a00
8419a81c14SSteve Longerbeam #define OV5640_REG_AEC_B50_STEP		0x3a08
8519a81c14SSteve Longerbeam #define OV5640_REG_AEC_B60_STEP		0x3a0a
8619a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0D		0x3a0d
8719a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0E		0x3a0e
8819a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0F		0x3a0f
8919a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL10		0x3a10
9019a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL11		0x3a11
9119a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1B		0x3a1b
9219a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1E		0x3a1e
9319a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1F		0x3a1f
9419a81c14SSteve Longerbeam #define OV5640_REG_HZ5060_CTRL00	0x3c00
9519a81c14SSteve Longerbeam #define OV5640_REG_HZ5060_CTRL01	0x3c01
9619a81c14SSteve Longerbeam #define OV5640_REG_SIGMADELTA_CTRL0C	0x3c0c
9719a81c14SSteve Longerbeam #define OV5640_REG_FRAME_CTRL01		0x4202
98e3ee691dSHugues Fruchet #define OV5640_REG_FORMAT_CONTROL00	0x4300
997cb013b1SChen-Yu Tsai #define OV5640_REG_VFIFO_HSIZE		0x4602
1007cb013b1SChen-Yu Tsai #define OV5640_REG_VFIFO_VSIZE		0x4604
1012b5c18f9SChen-Yu Tsai #define OV5640_REG_JPG_MODE_SELECT	0x4713
1024039b037SLad Prabhakar #define OV5640_REG_CCIR656_CTRL00	0x4730
103f22996dbSHugues Fruchet #define OV5640_REG_POLARITY_CTRL00	0x4740
10419a81c14SSteve Longerbeam #define OV5640_REG_MIPI_CTRL00		0x4800
10519a81c14SSteve Longerbeam #define OV5640_REG_DEBUG_MODE		0x4814
1066c957ed7SJacopo Mondi #define OV5640_REG_PCLK_PERIOD		0x4837
107e3ee691dSHugues Fruchet #define OV5640_REG_ISP_FORMAT_MUX_CTRL	0x501f
10819a81c14SSteve Longerbeam #define OV5640_REG_PRE_ISP_TEST_SET1	0x503d
10919a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL0		0x5580
11019a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL1		0x5581
11119a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL3		0x5583
11219a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL4		0x5584
11319a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL5		0x5585
11419a81c14SSteve Longerbeam #define OV5640_REG_AVG_READOUT		0x56a1
11519a81c14SSteve Longerbeam 
11619a81c14SSteve Longerbeam enum ov5640_mode_id {
11732ea5e05SHugues Fruchet 	OV5640_MODE_QQVGA_160_120 = 0,
11832ea5e05SHugues Fruchet 	OV5640_MODE_QCIF_176_144,
11919a81c14SSteve Longerbeam 	OV5640_MODE_QVGA_320_240,
12019a81c14SSteve Longerbeam 	OV5640_MODE_VGA_640_480,
12119a81c14SSteve Longerbeam 	OV5640_MODE_NTSC_720_480,
12219a81c14SSteve Longerbeam 	OV5640_MODE_PAL_720_576,
12319a81c14SSteve Longerbeam 	OV5640_MODE_XGA_1024_768,
12419a81c14SSteve Longerbeam 	OV5640_MODE_720P_1280_720,
12519a81c14SSteve Longerbeam 	OV5640_MODE_1080P_1920_1080,
12619a81c14SSteve Longerbeam 	OV5640_MODE_QSXGA_2592_1944,
12719a81c14SSteve Longerbeam 	OV5640_NUM_MODES,
12819a81c14SSteve Longerbeam };
12919a81c14SSteve Longerbeam 
13019a81c14SSteve Longerbeam enum ov5640_frame_rate {
13119a81c14SSteve Longerbeam 	OV5640_15_FPS = 0,
13219a81c14SSteve Longerbeam 	OV5640_30_FPS,
133e823fb16SMaxime Ripard 	OV5640_60_FPS,
13419a81c14SSteve Longerbeam 	OV5640_NUM_FRAMERATES,
13519a81c14SSteve Longerbeam };
13619a81c14SSteve Longerbeam 
13722845bf2SJacopo Mondi enum ov5640_pixel_rate_id {
13822845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_168M,
13922845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_148M,
14022845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_124M,
14122845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_96M,
14222845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_48M,
14322845bf2SJacopo Mondi 	OV5640_NUM_PIXEL_RATES,
14422845bf2SJacopo Mondi };
14522845bf2SJacopo Mondi 
14622845bf2SJacopo Mondi /*
14722845bf2SJacopo Mondi  * The chip manual suggests 24/48/96/192 MHz pixel clocks.
14822845bf2SJacopo Mondi  *
14922845bf2SJacopo Mondi  * 192MHz exceeds the sysclk limits; use 168MHz as maximum pixel rate for
15022845bf2SJacopo Mondi  * full resolution mode @15 FPS.
15122845bf2SJacopo Mondi  */
15222845bf2SJacopo Mondi static const u32 ov5640_pixel_rates[] = {
15322845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_168M] = 168000000,
15422845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_148M] = 148000000,
15522845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_124M] = 124000000,
15622845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_96M] = 96000000,
15722845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_48M] = 48000000,
15822845bf2SJacopo Mondi };
15922845bf2SJacopo Mondi 
1607a3b8d4bSJacopo Mondi /*
1617a3b8d4bSJacopo Mondi  * MIPI CSI-2 link frequencies.
1627a3b8d4bSJacopo Mondi  *
1637a3b8d4bSJacopo Mondi  * Derived from the above defined pixel rate for bpp = (8, 16, 24) and
1647a3b8d4bSJacopo Mondi  * data_lanes = (1, 2)
1657a3b8d4bSJacopo Mondi  *
1667a3b8d4bSJacopo Mondi  * link_freq = (pixel_rate * bpp) / (2 * data_lanes)
1677a3b8d4bSJacopo Mondi  */
1687a3b8d4bSJacopo Mondi static const s64 ov5640_csi2_link_freqs[] = {
1697a3b8d4bSJacopo Mondi 	992000000, 888000000, 768000000, 744000000, 672000000, 672000000,
1707a3b8d4bSJacopo Mondi 	592000000, 592000000, 576000000, 576000000, 496000000, 496000000,
1717a3b8d4bSJacopo Mondi 	384000000, 384000000, 384000000, 336000000, 296000000, 288000000,
1727a3b8d4bSJacopo Mondi 	248000000, 192000000, 192000000, 192000000, 96000000,
1737a3b8d4bSJacopo Mondi };
1747a3b8d4bSJacopo Mondi 
1757a3b8d4bSJacopo Mondi /* Link freq for default mode: UYVY 16 bpp, 2 data lanes. */
1767a3b8d4bSJacopo Mondi #define OV5640_DEFAULT_LINK_FREQ	13
1777a3b8d4bSJacopo Mondi 
178b7ed3abdSLoic Poulain enum ov5640_format_mux {
179b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_YUV422 = 0,
180b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_RGB,
181b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_DITHER,
182b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_RAW_DPC,
183b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_SNR_RAW,
184b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_RAW_CIP,
185b7ed3abdSLoic Poulain };
186b7ed3abdSLoic Poulain 
1872d7671f6SJacopo Mondi static const struct ov5640_pixfmt {
188e3ee691dSHugues Fruchet 	u32 code;
189e3ee691dSHugues Fruchet 	u32 colorspace;
1902d7671f6SJacopo Mondi 	u8 bpp;
1912d7671f6SJacopo Mondi } ov5640_formats[] = {
1922d7671f6SJacopo Mondi 	{
1932d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_JPEG_1X8,
1942d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_JPEG,
1952d7671f6SJacopo Mondi 		.bpp = 16,
1962d7671f6SJacopo Mondi 	}, {
1972d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_UYVY8_2X8,
1982d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
1992d7671f6SJacopo Mondi 		.bpp = 16,
2002d7671f6SJacopo Mondi 	}, {
2012d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_UYVY8_1X16,
2022d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2032d7671f6SJacopo Mondi 		.bpp = 16,
2042d7671f6SJacopo Mondi 	}, {
2052d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_YUYV8_2X8,
2062d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2072d7671f6SJacopo Mondi 		.bpp = 16,
2082d7671f6SJacopo Mondi 	}, {
2092d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_YUYV8_1X16,
2102d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2112d7671f6SJacopo Mondi 		.bpp = 16,
2122d7671f6SJacopo Mondi 	}, {
2132d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_RGB565_2X8_LE,
2142d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2152d7671f6SJacopo Mondi 		.bpp = 16,
2162d7671f6SJacopo Mondi 	}, {
2172d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_RGB565_2X8_BE,
2182d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2192d7671f6SJacopo Mondi 		.bpp = 16,
2202d7671f6SJacopo Mondi 	}, {
2212d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_SBGGR8_1X8,
2222d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2232d7671f6SJacopo Mondi 		.bpp = 8,
2242d7671f6SJacopo Mondi 	}, {
2252d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_SGBRG8_1X8,
2262d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2272d7671f6SJacopo Mondi 		.bpp = 8
2282d7671f6SJacopo Mondi 	}, {
2292d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_SGRBG8_1X8,
2302d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2312d7671f6SJacopo Mondi 		.bpp = 8,
2322d7671f6SJacopo Mondi 	}, {
2332d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_SRGGB8_1X8,
2342d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2352d7671f6SJacopo Mondi 		.bpp = 8,
2362d7671f6SJacopo Mondi 	},
237e3ee691dSHugues Fruchet };
238e3ee691dSHugues Fruchet 
2393c28588fSJacopo Mondi static u32 ov5640_code_to_bpp(u32 code)
2403c28588fSJacopo Mondi {
2413c28588fSJacopo Mondi 	unsigned int i;
2423c28588fSJacopo Mondi 
2433c28588fSJacopo Mondi 	for (i = 0; i < ARRAY_SIZE(ov5640_formats); ++i) {
2443c28588fSJacopo Mondi 		if (ov5640_formats[i].code == code)
2453c28588fSJacopo Mondi 			return ov5640_formats[i].bpp;
2463c28588fSJacopo Mondi 	}
2473c28588fSJacopo Mondi 
2483c28588fSJacopo Mondi 	return 0;
2493c28588fSJacopo Mondi }
2503c28588fSJacopo Mondi 
25119a81c14SSteve Longerbeam /*
25219a81c14SSteve Longerbeam  * FIXME: remove this when a subdev API becomes available
25319a81c14SSteve Longerbeam  * to set the MIPI CSI-2 virtual channel.
25419a81c14SSteve Longerbeam  */
25519a81c14SSteve Longerbeam static unsigned int virtual_channel;
2568670d70aSHugues Fruchet module_param(virtual_channel, uint, 0444);
25719a81c14SSteve Longerbeam MODULE_PARM_DESC(virtual_channel,
25819a81c14SSteve Longerbeam 		 "MIPI CSI-2 virtual channel (0..3), default 0");
25919a81c14SSteve Longerbeam 
26019a81c14SSteve Longerbeam static const int ov5640_framerates[] = {
26119a81c14SSteve Longerbeam 	[OV5640_15_FPS] = 15,
26219a81c14SSteve Longerbeam 	[OV5640_30_FPS] = 30,
263e823fb16SMaxime Ripard 	[OV5640_60_FPS] = 60,
26419a81c14SSteve Longerbeam };
26519a81c14SSteve Longerbeam 
26619a81c14SSteve Longerbeam /* regulator supplies */
26719a81c14SSteve Longerbeam static const char * const ov5640_supply_name[] = {
26841d8d7f5SHugues Fruchet 	"DOVDD", /* Digital I/O (1.8V) supply */
26919a81c14SSteve Longerbeam 	"AVDD",  /* Analog (2.8V) supply */
27024c8ac89SFabio Estevam 	"DVDD",  /* Digital Core (1.5V) supply */
27119a81c14SSteve Longerbeam };
27219a81c14SSteve Longerbeam 
27319a81c14SSteve Longerbeam #define OV5640_NUM_SUPPLIES ARRAY_SIZE(ov5640_supply_name)
27419a81c14SSteve Longerbeam 
27519a81c14SSteve Longerbeam /*
27619a81c14SSteve Longerbeam  * Image size under 1280 * 960 are SUBSAMPLING
27719a81c14SSteve Longerbeam  * Image size upper 1280 * 960 are SCALING
27819a81c14SSteve Longerbeam  */
27919a81c14SSteve Longerbeam enum ov5640_downsize_mode {
28019a81c14SSteve Longerbeam 	SUBSAMPLING,
28119a81c14SSteve Longerbeam 	SCALING,
28219a81c14SSteve Longerbeam };
28319a81c14SSteve Longerbeam 
28419a81c14SSteve Longerbeam struct reg_value {
28519a81c14SSteve Longerbeam 	u16 reg_addr;
28619a81c14SSteve Longerbeam 	u8 val;
28719a81c14SSteve Longerbeam 	u8 mask;
28819a81c14SSteve Longerbeam 	u32 delay_ms;
28919a81c14SSteve Longerbeam };
29019a81c14SSteve Longerbeam 
2915113d5b3SJacopo Mondi struct ov5640_timings {
2923145efcdSJacopo Mondi 	/* Analog crop rectangle. */
2933145efcdSJacopo Mondi 	struct v4l2_rect analog_crop;
2943145efcdSJacopo Mondi 	/* Visibile crop: from analog crop top-left corner. */
2953145efcdSJacopo Mondi 	struct v4l2_rect crop;
2965113d5b3SJacopo Mondi 	/* Total pixels per line: width + fixed hblank. */
297476dec01SMaxime Ripard 	u32 htot;
2985113d5b3SJacopo Mondi 	/* Default vertical blanking: frame height = height + vblank. */
2993145efcdSJacopo Mondi 	u32 vblank_def;
3005113d5b3SJacopo Mondi };
3015113d5b3SJacopo Mondi 
3025113d5b3SJacopo Mondi struct ov5640_mode_info {
3035113d5b3SJacopo Mondi 	enum ov5640_mode_id id;
3045113d5b3SJacopo Mondi 	enum ov5640_downsize_mode dn_mode;
3055113d5b3SJacopo Mondi 	enum ov5640_pixel_rate_id pixel_rate;
3065113d5b3SJacopo Mondi 
3075113d5b3SJacopo Mondi 	unsigned int width;
3085113d5b3SJacopo Mondi 	unsigned int height;
3095113d5b3SJacopo Mondi 
3105113d5b3SJacopo Mondi 	struct ov5640_timings dvp_timings;
3115113d5b3SJacopo Mondi 	struct ov5640_timings csi2_timings;
3125113d5b3SJacopo Mondi 
31319a81c14SSteve Longerbeam 	const struct reg_value *reg_data;
31419a81c14SSteve Longerbeam 	u32 reg_data_size;
3155113d5b3SJacopo Mondi 
3165113d5b3SJacopo Mondi 	/* Used by s_frame_interval only. */
3175554c80eSAdam Ford 	u32 max_fps;
31819a81c14SSteve Longerbeam };
31919a81c14SSteve Longerbeam 
32019a81c14SSteve Longerbeam struct ov5640_ctrls {
32119a81c14SSteve Longerbeam 	struct v4l2_ctrl_handler handler;
322cc196e48SBenoit Parrot 	struct v4l2_ctrl *pixel_rate;
3237a3b8d4bSJacopo Mondi 	struct v4l2_ctrl *link_freq;
32419a81c14SSteve Longerbeam 	struct {
32519a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_exp;
32619a81c14SSteve Longerbeam 		struct v4l2_ctrl *exposure;
32719a81c14SSteve Longerbeam 	};
32819a81c14SSteve Longerbeam 	struct {
32919a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_wb;
33019a81c14SSteve Longerbeam 		struct v4l2_ctrl *blue_balance;
33119a81c14SSteve Longerbeam 		struct v4l2_ctrl *red_balance;
33219a81c14SSteve Longerbeam 	};
33319a81c14SSteve Longerbeam 	struct {
33419a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_gain;
33519a81c14SSteve Longerbeam 		struct v4l2_ctrl *gain;
33619a81c14SSteve Longerbeam 	};
33719a81c14SSteve Longerbeam 	struct v4l2_ctrl *brightness;
3381068fecaSMylène Josserand 	struct v4l2_ctrl *light_freq;
33919a81c14SSteve Longerbeam 	struct v4l2_ctrl *saturation;
34019a81c14SSteve Longerbeam 	struct v4l2_ctrl *contrast;
34119a81c14SSteve Longerbeam 	struct v4l2_ctrl *hue;
34219a81c14SSteve Longerbeam 	struct v4l2_ctrl *test_pattern;
343ce85705aSHugues Fruchet 	struct v4l2_ctrl *hflip;
344ce85705aSHugues Fruchet 	struct v4l2_ctrl *vflip;
34519a81c14SSteve Longerbeam };
34619a81c14SSteve Longerbeam 
34719a81c14SSteve Longerbeam struct ov5640_dev {
34819a81c14SSteve Longerbeam 	struct i2c_client *i2c_client;
34919a81c14SSteve Longerbeam 	struct v4l2_subdev sd;
35019a81c14SSteve Longerbeam 	struct media_pad pad;
35119a81c14SSteve Longerbeam 	struct v4l2_fwnode_endpoint ep; /* the parsed DT endpoint info */
35219a81c14SSteve Longerbeam 	struct clk *xclk; /* system clock to OV5640 */
35319a81c14SSteve Longerbeam 	u32 xclk_freq;
35419a81c14SSteve Longerbeam 
35519a81c14SSteve Longerbeam 	struct regulator_bulk_data supplies[OV5640_NUM_SUPPLIES];
35619a81c14SSteve Longerbeam 	struct gpio_desc *reset_gpio;
35719a81c14SSteve Longerbeam 	struct gpio_desc *pwdn_gpio;
358c3f3ba3eSHugues Fruchet 	bool   upside_down;
35919a81c14SSteve Longerbeam 
36019a81c14SSteve Longerbeam 	/* lock to protect all members below */
36119a81c14SSteve Longerbeam 	struct mutex lock;
36219a81c14SSteve Longerbeam 
36319a81c14SSteve Longerbeam 	int power_count;
36419a81c14SSteve Longerbeam 
36519a81c14SSteve Longerbeam 	struct v4l2_mbus_framefmt fmt;
366fb98e29fSHugues Fruchet 	bool pending_fmt_change;
36719a81c14SSteve Longerbeam 
36819a81c14SSteve Longerbeam 	const struct ov5640_mode_info *current_mode;
369985cdcb0SHugues Fruchet 	const struct ov5640_mode_info *last_mode;
37019a81c14SSteve Longerbeam 	enum ov5640_frame_rate current_fr;
37119a81c14SSteve Longerbeam 	struct v4l2_fract frame_interval;
3723c28588fSJacopo Mondi 	s64 current_link_freq;
37319a81c14SSteve Longerbeam 
37419a81c14SSteve Longerbeam 	struct ov5640_ctrls ctrls;
37519a81c14SSteve Longerbeam 
37619a81c14SSteve Longerbeam 	u32 prev_sysclk, prev_hts;
37719a81c14SSteve Longerbeam 	u32 ae_low, ae_high, ae_target;
37819a81c14SSteve Longerbeam 
37919a81c14SSteve Longerbeam 	bool pending_mode_change;
38019a81c14SSteve Longerbeam 	bool streaming;
38119a81c14SSteve Longerbeam };
38219a81c14SSteve Longerbeam 
38319a81c14SSteve Longerbeam static inline struct ov5640_dev *to_ov5640_dev(struct v4l2_subdev *sd)
38419a81c14SSteve Longerbeam {
38519a81c14SSteve Longerbeam 	return container_of(sd, struct ov5640_dev, sd);
38619a81c14SSteve Longerbeam }
38719a81c14SSteve Longerbeam 
38819a81c14SSteve Longerbeam static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
38919a81c14SSteve Longerbeam {
39019a81c14SSteve Longerbeam 	return &container_of(ctrl->handler, struct ov5640_dev,
39119a81c14SSteve Longerbeam 			     ctrls.handler)->sd;
39219a81c14SSteve Longerbeam }
39319a81c14SSteve Longerbeam 
3948e823f5cSJacopo Mondi static inline bool ov5640_is_csi2(const struct ov5640_dev *sensor)
3958e823f5cSJacopo Mondi {
3968e823f5cSJacopo Mondi 	return sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY;
3978e823f5cSJacopo Mondi }
3988e823f5cSJacopo Mondi 
39919a81c14SSteve Longerbeam /*
40019a81c14SSteve Longerbeam  * FIXME: all of these register tables are likely filled with
40119a81c14SSteve Longerbeam  * entries that set the register to their power-on default values,
40219a81c14SSteve Longerbeam  * and which are otherwise not touched by this driver. Those entries
40319a81c14SSteve Longerbeam  * should be identified and removed to speed register load time
40419a81c14SSteve Longerbeam  * over i2c.
40519a81c14SSteve Longerbeam  */
406fb98e29fSHugues Fruchet /* YUV422 UYVY VGA@30fps */
407*e4359019SJacopo Mondi static const struct reg_value ov5640_init_setting[] = {
40819a81c14SSteve Longerbeam 	{0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0},
409576f5d4bSLad Prabhakar 	{0x3103, 0x03, 0, 0}, {0x3630, 0x36, 0, 0},
41019a81c14SSteve Longerbeam 	{0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0},
41119a81c14SSteve Longerbeam 	{0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0},
41219a81c14SSteve Longerbeam 	{0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0},
41319a81c14SSteve Longerbeam 	{0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, {0x3906, 0x10, 0, 0},
41419a81c14SSteve Longerbeam 	{0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, {0x3600, 0x08, 0, 0},
41519a81c14SSteve Longerbeam 	{0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, {0x3620, 0x52, 0, 0},
41619a81c14SSteve Longerbeam 	{0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, {0x3a13, 0x43, 0, 0},
41719a81c14SSteve Longerbeam 	{0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3635, 0x13, 0, 0},
41819a81c14SSteve Longerbeam 	{0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, {0x3622, 0x01, 0, 0},
41919a81c14SSteve Longerbeam 	{0x3c01, 0xa4, 0, 0}, {0x3c04, 0x28, 0, 0}, {0x3c05, 0x98, 0, 0},
42019a81c14SSteve Longerbeam 	{0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0},
42119a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
42219a81c14SSteve Longerbeam 	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
4233145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
42419a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
42519a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
42619a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
42719a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
42819a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
42919a81c14SSteve Longerbeam 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0},
43019a81c14SSteve Longerbeam 	{0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0},
431aa4bb8b8SJacopo Mondi 	{0x302e, 0x08, 0, 0}, {0x4300, 0x3f, 0, 0},
4322b5c18f9SChen-Yu Tsai 	{0x501f, 0x00, 0, 0}, {0x4407, 0x04, 0, 0},
43319a81c14SSteve Longerbeam 	{0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
434aa4bb8b8SJacopo Mondi 	{0x4837, 0x0a, 0, 0}, {0x3824, 0x02, 0, 0},
43519a81c14SSteve Longerbeam 	{0x5000, 0xa7, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0},
43619a81c14SSteve Longerbeam 	{0x5181, 0xf2, 0, 0}, {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0},
43719a81c14SSteve Longerbeam 	{0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0},
43819a81c14SSteve Longerbeam 	{0x5187, 0x09, 0, 0}, {0x5188, 0x09, 0, 0}, {0x5189, 0x88, 0, 0},
43919a81c14SSteve Longerbeam 	{0x518a, 0x54, 0, 0}, {0x518b, 0xee, 0, 0}, {0x518c, 0xb2, 0, 0},
44019a81c14SSteve Longerbeam 	{0x518d, 0x50, 0, 0}, {0x518e, 0x34, 0, 0}, {0x518f, 0x6b, 0, 0},
44119a81c14SSteve Longerbeam 	{0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0},
44219a81c14SSteve Longerbeam 	{0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0},
44319a81c14SSteve Longerbeam 	{0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0},
44419a81c14SSteve Longerbeam 	{0x5199, 0x6c, 0, 0}, {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0},
44519a81c14SSteve Longerbeam 	{0x519c, 0x09, 0, 0}, {0x519d, 0x2b, 0, 0}, {0x519e, 0x38, 0, 0},
44619a81c14SSteve Longerbeam 	{0x5381, 0x1e, 0, 0}, {0x5382, 0x5b, 0, 0}, {0x5383, 0x08, 0, 0},
44719a81c14SSteve Longerbeam 	{0x5384, 0x0a, 0, 0}, {0x5385, 0x7e, 0, 0}, {0x5386, 0x88, 0, 0},
44819a81c14SSteve Longerbeam 	{0x5387, 0x7c, 0, 0}, {0x5388, 0x6c, 0, 0}, {0x5389, 0x10, 0, 0},
44919a81c14SSteve Longerbeam 	{0x538a, 0x01, 0, 0}, {0x538b, 0x98, 0, 0}, {0x5300, 0x08, 0, 0},
45019a81c14SSteve Longerbeam 	{0x5301, 0x30, 0, 0}, {0x5302, 0x10, 0, 0}, {0x5303, 0x00, 0, 0},
45119a81c14SSteve Longerbeam 	{0x5304, 0x08, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x08, 0, 0},
45219a81c14SSteve Longerbeam 	{0x5307, 0x16, 0, 0}, {0x5309, 0x08, 0, 0}, {0x530a, 0x30, 0, 0},
45319a81c14SSteve Longerbeam 	{0x530b, 0x04, 0, 0}, {0x530c, 0x06, 0, 0}, {0x5480, 0x01, 0, 0},
45419a81c14SSteve Longerbeam 	{0x5481, 0x08, 0, 0}, {0x5482, 0x14, 0, 0}, {0x5483, 0x28, 0, 0},
45519a81c14SSteve Longerbeam 	{0x5484, 0x51, 0, 0}, {0x5485, 0x65, 0, 0}, {0x5486, 0x71, 0, 0},
45619a81c14SSteve Longerbeam 	{0x5487, 0x7d, 0, 0}, {0x5488, 0x87, 0, 0}, {0x5489, 0x91, 0, 0},
45719a81c14SSteve Longerbeam 	{0x548a, 0x9a, 0, 0}, {0x548b, 0xaa, 0, 0}, {0x548c, 0xb8, 0, 0},
45819a81c14SSteve Longerbeam 	{0x548d, 0xcd, 0, 0}, {0x548e, 0xdd, 0, 0}, {0x548f, 0xea, 0, 0},
45919a81c14SSteve Longerbeam 	{0x5490, 0x1d, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5583, 0x40, 0, 0},
46019a81c14SSteve Longerbeam 	{0x5584, 0x10, 0, 0}, {0x5589, 0x10, 0, 0}, {0x558a, 0x00, 0, 0},
46119a81c14SSteve Longerbeam 	{0x558b, 0xf8, 0, 0}, {0x5800, 0x23, 0, 0}, {0x5801, 0x14, 0, 0},
46219a81c14SSteve Longerbeam 	{0x5802, 0x0f, 0, 0}, {0x5803, 0x0f, 0, 0}, {0x5804, 0x12, 0, 0},
46319a81c14SSteve Longerbeam 	{0x5805, 0x26, 0, 0}, {0x5806, 0x0c, 0, 0}, {0x5807, 0x08, 0, 0},
46419a81c14SSteve Longerbeam 	{0x5808, 0x05, 0, 0}, {0x5809, 0x05, 0, 0}, {0x580a, 0x08, 0, 0},
46519a81c14SSteve Longerbeam 	{0x580b, 0x0d, 0, 0}, {0x580c, 0x08, 0, 0}, {0x580d, 0x03, 0, 0},
46619a81c14SSteve Longerbeam 	{0x580e, 0x00, 0, 0}, {0x580f, 0x00, 0, 0}, {0x5810, 0x03, 0, 0},
46719a81c14SSteve Longerbeam 	{0x5811, 0x09, 0, 0}, {0x5812, 0x07, 0, 0}, {0x5813, 0x03, 0, 0},
46819a81c14SSteve Longerbeam 	{0x5814, 0x00, 0, 0}, {0x5815, 0x01, 0, 0}, {0x5816, 0x03, 0, 0},
46919a81c14SSteve Longerbeam 	{0x5817, 0x08, 0, 0}, {0x5818, 0x0d, 0, 0}, {0x5819, 0x08, 0, 0},
47019a81c14SSteve Longerbeam 	{0x581a, 0x05, 0, 0}, {0x581b, 0x06, 0, 0}, {0x581c, 0x08, 0, 0},
47119a81c14SSteve Longerbeam 	{0x581d, 0x0e, 0, 0}, {0x581e, 0x29, 0, 0}, {0x581f, 0x17, 0, 0},
47219a81c14SSteve Longerbeam 	{0x5820, 0x11, 0, 0}, {0x5821, 0x11, 0, 0}, {0x5822, 0x15, 0, 0},
47319a81c14SSteve Longerbeam 	{0x5823, 0x28, 0, 0}, {0x5824, 0x46, 0, 0}, {0x5825, 0x26, 0, 0},
47419a81c14SSteve Longerbeam 	{0x5826, 0x08, 0, 0}, {0x5827, 0x26, 0, 0}, {0x5828, 0x64, 0, 0},
47519a81c14SSteve Longerbeam 	{0x5829, 0x26, 0, 0}, {0x582a, 0x24, 0, 0}, {0x582b, 0x22, 0, 0},
47619a81c14SSteve Longerbeam 	{0x582c, 0x24, 0, 0}, {0x582d, 0x24, 0, 0}, {0x582e, 0x06, 0, 0},
47719a81c14SSteve Longerbeam 	{0x582f, 0x22, 0, 0}, {0x5830, 0x40, 0, 0}, {0x5831, 0x42, 0, 0},
47819a81c14SSteve Longerbeam 	{0x5832, 0x24, 0, 0}, {0x5833, 0x26, 0, 0}, {0x5834, 0x24, 0, 0},
47919a81c14SSteve Longerbeam 	{0x5835, 0x22, 0, 0}, {0x5836, 0x22, 0, 0}, {0x5837, 0x26, 0, 0},
48019a81c14SSteve Longerbeam 	{0x5838, 0x44, 0, 0}, {0x5839, 0x24, 0, 0}, {0x583a, 0x26, 0, 0},
48119a81c14SSteve Longerbeam 	{0x583b, 0x28, 0, 0}, {0x583c, 0x42, 0, 0}, {0x583d, 0xce, 0, 0},
48219a81c14SSteve Longerbeam 	{0x5025, 0x00, 0, 0}, {0x3a0f, 0x30, 0, 0}, {0x3a10, 0x28, 0, 0},
48319a81c14SSteve Longerbeam 	{0x3a1b, 0x30, 0, 0}, {0x3a1e, 0x26, 0, 0}, {0x3a11, 0x60, 0, 0},
48419a81c14SSteve Longerbeam 	{0x3a1f, 0x14, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3c00, 0x04, 0, 300},
48519a81c14SSteve Longerbeam };
48619a81c14SSteve Longerbeam 
487db15c195SJacopo Mondi static const struct reg_value ov5640_setting_low_res[] = {
488c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
48919a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
490ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
4913145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
49219a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
49319a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
49419a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
49519a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
49619a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
4972b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
498e15197bdSJacopo Mondi 	{0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0},
49919a81c14SSteve Longerbeam };
50019a81c14SSteve Longerbeam 
501086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_720P_1280_720[] = {
502c14d107eSMaxime Ripard 	{0x3c07, 0x07, 0, 0},
50319a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
504ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
5053145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
50619a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
50719a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0},
50819a81c14SSteve Longerbeam 	{0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0},
50919a81c14SSteve Longerbeam 	{0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0},
51019a81c14SSteve Longerbeam 	{0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0},
5112b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
51219a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
51319a81c14SSteve Longerbeam 	{0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0},
51419a81c14SSteve Longerbeam };
51519a81c14SSteve Longerbeam 
516086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_1080P_1920_1080[] = {
517c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
51819a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
519ce85705aSHugues Fruchet 	{0x3814, 0x11, 0, 0},
5203145efcdSJacopo Mondi 	{0x3815, 0x11, 0, 0},
52119a81c14SSteve Longerbeam 	{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
52219a81c14SSteve Longerbeam 	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
52319a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
52419a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
52519a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5262b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0},
52719a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
528c14d107eSMaxime Ripard 	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0},
529c14d107eSMaxime Ripard 	{0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0},
53019a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
531476dec01SMaxime Ripard 	{0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0},
53219a81c14SSteve Longerbeam 	{0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0},
53319a81c14SSteve Longerbeam 	{0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0},
53419a81c14SSteve Longerbeam 	{0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0},
5352b5c18f9SChen-Yu Tsai 	{0x3a15, 0x60, 0, 0}, {0x4407, 0x04, 0, 0},
53619a81c14SSteve Longerbeam 	{0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0},
53792b9096cSBenoit Parrot 	{0x4005, 0x1a, 0, 0},
53819a81c14SSteve Longerbeam };
53919a81c14SSteve Longerbeam 
540086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_QSXGA_2592_1944[] = {
541c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
54219a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
543ce85705aSHugues Fruchet 	{0x3814, 0x11, 0, 0},
5443145efcdSJacopo Mondi 	{0x3815, 0x11, 0, 0},
54519a81c14SSteve Longerbeam 	{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
54619a81c14SSteve Longerbeam 	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
54719a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
54819a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
54919a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5502b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0},
55119a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
55219a81c14SSteve Longerbeam 	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70},
55319a81c14SSteve Longerbeam };
55419a81c14SSteve Longerbeam 
5555113d5b3SJacopo Mondi static const struct ov5640_mode_info ov5640_mode_data[OV5640_NUM_MODES] = {
5568409d017SJacopo Mondi 	{
5578409d017SJacopo Mondi 		/* 160x120 */
5583145efcdSJacopo Mondi 		.id		= OV5640_MODE_QQVGA_160_120,
5593145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
5603145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
5615113d5b3SJacopo Mondi 		.width		= 160,
5625113d5b3SJacopo Mondi 		.height		= 120,
5635113d5b3SJacopo Mondi 		.dvp_timings = {
5643145efcdSJacopo Mondi 			.analog_crop = {
5653145efcdSJacopo Mondi 				.left	= 0,
5663145efcdSJacopo Mondi 				.top	= 4,
5673145efcdSJacopo Mondi 				.width	= 2624,
5683145efcdSJacopo Mondi 				.height	= 1944,
5693145efcdSJacopo Mondi 			},
5703145efcdSJacopo Mondi 			.crop = {
5713145efcdSJacopo Mondi 				.left	= 16,
5723145efcdSJacopo Mondi 				.top	= 6,
5733145efcdSJacopo Mondi 				.width	= 160,
5743145efcdSJacopo Mondi 				.height	= 120,
5753145efcdSJacopo Mondi 			},
5763145efcdSJacopo Mondi 			.htot		= 1896,
5773145efcdSJacopo Mondi 			.vblank_def	= 864,
5785113d5b3SJacopo Mondi 		},
5795113d5b3SJacopo Mondi 		.csi2_timings = {
5805113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
5815113d5b3SJacopo Mondi 			.analog_crop = {
5825113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
5835113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
5845113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
5855113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
5865113d5b3SJacopo Mondi 			},
5875113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
5885113d5b3SJacopo Mondi 			.crop = {
5895113d5b3SJacopo Mondi 				.left	= 2,
5905113d5b3SJacopo Mondi 				.top	= 4,
5915113d5b3SJacopo Mondi 				.width	= 160,
5925113d5b3SJacopo Mondi 				.height	= 120,
5935113d5b3SJacopo Mondi 			},
5945113d5b3SJacopo Mondi 			.htot		= 1896,
5955113d5b3SJacopo Mondi 			.vblank_def	= 864,
5965113d5b3SJacopo Mondi 		},
597db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
598db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
5993145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
6008409d017SJacopo Mondi 	}, {
6018409d017SJacopo Mondi 		/* 176x144 */
6023145efcdSJacopo Mondi 		.id		= OV5640_MODE_QCIF_176_144,
6033145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
6043145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
6055113d5b3SJacopo Mondi 		.width		= 176,
6065113d5b3SJacopo Mondi 		.height		= 144,
6075113d5b3SJacopo Mondi 		.dvp_timings = {
6083145efcdSJacopo Mondi 			.analog_crop = {
6093145efcdSJacopo Mondi 				.left	= 0,
6103145efcdSJacopo Mondi 				.top	= 4,
6113145efcdSJacopo Mondi 				.width	= 2624,
6123145efcdSJacopo Mondi 				.height	= 1944,
6133145efcdSJacopo Mondi 			},
6143145efcdSJacopo Mondi 			.crop = {
6153145efcdSJacopo Mondi 				.left	= 16,
6163145efcdSJacopo Mondi 				.top	= 6,
6173145efcdSJacopo Mondi 				.width	= 176,
6183145efcdSJacopo Mondi 				.height	= 144,
6193145efcdSJacopo Mondi 			},
6203145efcdSJacopo Mondi 			.htot		= 1896,
6213145efcdSJacopo Mondi 			.vblank_def	= 840,
6225113d5b3SJacopo Mondi 		},
6235113d5b3SJacopo Mondi 		.csi2_timings = {
6245113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
6255113d5b3SJacopo Mondi 			.analog_crop = {
6265113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
6275113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
6285113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
6295113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
6305113d5b3SJacopo Mondi 			},
6315113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
6325113d5b3SJacopo Mondi 			.crop = {
6335113d5b3SJacopo Mondi 				.left	= 2,
6345113d5b3SJacopo Mondi 				.top	= 4,
6355113d5b3SJacopo Mondi 				.width	= 176,
6365113d5b3SJacopo Mondi 				.height	= 144,
6375113d5b3SJacopo Mondi 			},
6385113d5b3SJacopo Mondi 			.htot		= 1896,
6395113d5b3SJacopo Mondi 			.vblank_def	= 840,
6405113d5b3SJacopo Mondi 		},
641db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
642db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
6433145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
6448409d017SJacopo Mondi 	}, {
6458409d017SJacopo Mondi 		/* 320x240 */
6463145efcdSJacopo Mondi 		.id		= OV5640_MODE_QVGA_320_240,
6473145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
6485113d5b3SJacopo Mondi 		.width		= 320,
6495113d5b3SJacopo Mondi 		.height		= 240,
6503145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
6515113d5b3SJacopo Mondi 		.dvp_timings = {
6523145efcdSJacopo Mondi 			.analog_crop = {
6533145efcdSJacopo Mondi 				.left	= 0,
6543145efcdSJacopo Mondi 				.top	= 4,
6553145efcdSJacopo Mondi 				.width	= 2624,
6563145efcdSJacopo Mondi 				.height	= 1944,
6573145efcdSJacopo Mondi 			},
6583145efcdSJacopo Mondi 			.crop = {
6593145efcdSJacopo Mondi 				.left	= 16,
6603145efcdSJacopo Mondi 				.top	= 6,
6613145efcdSJacopo Mondi 				.width	= 320,
6623145efcdSJacopo Mondi 				.height	= 240,
6633145efcdSJacopo Mondi 			},
6643145efcdSJacopo Mondi 			.htot		= 1896,
6653145efcdSJacopo Mondi 			.vblank_def	= 744,
6665113d5b3SJacopo Mondi 		},
6675113d5b3SJacopo Mondi 		.csi2_timings = {
6685113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
6695113d5b3SJacopo Mondi 			.analog_crop = {
6705113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
6715113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
6725113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
6735113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
6745113d5b3SJacopo Mondi 			},
6755113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
6765113d5b3SJacopo Mondi 			.crop = {
6775113d5b3SJacopo Mondi 				.left	= 2,
6785113d5b3SJacopo Mondi 				.top	= 4,
6795113d5b3SJacopo Mondi 				.width	= 320,
6805113d5b3SJacopo Mondi 				.height	= 240,
6815113d5b3SJacopo Mondi 			},
6825113d5b3SJacopo Mondi 			.htot		= 1896,
6835113d5b3SJacopo Mondi 			.vblank_def	= 744,
6845113d5b3SJacopo Mondi 		},
685db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
686db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
6873145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
6888409d017SJacopo Mondi 	}, {
6898409d017SJacopo Mondi 		/* 640x480 */
6903145efcdSJacopo Mondi 		.id		= OV5640_MODE_VGA_640_480,
6913145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
6923145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
6935113d5b3SJacopo Mondi 		.width		= 640,
6945113d5b3SJacopo Mondi 		.height		= 480,
6955113d5b3SJacopo Mondi 		.dvp_timings = {
6963145efcdSJacopo Mondi 			.analog_crop = {
6973145efcdSJacopo Mondi 				.left	= 0,
6983145efcdSJacopo Mondi 				.top	= 4,
6993145efcdSJacopo Mondi 				.width	= 2624,
7003145efcdSJacopo Mondi 				.height	= 1944,
7013145efcdSJacopo Mondi 			},
7023145efcdSJacopo Mondi 			.crop = {
7033145efcdSJacopo Mondi 				.left	= 16,
7043145efcdSJacopo Mondi 				.top	= 6,
7053145efcdSJacopo Mondi 				.width	= 640,
7063145efcdSJacopo Mondi 				.height	= 480,
7073145efcdSJacopo Mondi 			},
7083145efcdSJacopo Mondi 			.htot		= 1896,
7093145efcdSJacopo Mondi 			.vblank_def	= 600,
7105113d5b3SJacopo Mondi 		},
7115113d5b3SJacopo Mondi 		.csi2_timings = {
7125113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
7135113d5b3SJacopo Mondi 			.analog_crop = {
7145113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
7155113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
7165113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
7175113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
7185113d5b3SJacopo Mondi 			},
7195113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
7205113d5b3SJacopo Mondi 			.crop = {
7215113d5b3SJacopo Mondi 				.left	= 2,
7225113d5b3SJacopo Mondi 				.top	= 4,
7235113d5b3SJacopo Mondi 				.width	= 640,
7245113d5b3SJacopo Mondi 				.height	= 480,
7255113d5b3SJacopo Mondi 			},
7265113d5b3SJacopo Mondi 			.htot		= 1896,
7275113d5b3SJacopo Mondi 			.vblank_def	= 600,
7285113d5b3SJacopo Mondi 		},
729db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
730db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
7313145efcdSJacopo Mondi 		.max_fps	= OV5640_60_FPS
7328409d017SJacopo Mondi 	}, {
7338409d017SJacopo Mondi 		/* 720x480 */
7343145efcdSJacopo Mondi 		.id		= OV5640_MODE_NTSC_720_480,
7353145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
7365113d5b3SJacopo Mondi 		.width		= 720,
7375113d5b3SJacopo Mondi 		.height		= 480,
7383145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
7395113d5b3SJacopo Mondi 		.dvp_timings = {
7403145efcdSJacopo Mondi 			.analog_crop = {
7413145efcdSJacopo Mondi 				.left	= 0,
7423145efcdSJacopo Mondi 				.top	= 4,
7433145efcdSJacopo Mondi 				.width	= 2624,
7443145efcdSJacopo Mondi 				.height	= 1944,
7453145efcdSJacopo Mondi 			},
7463145efcdSJacopo Mondi 			.crop = {
747e74ef55bSJacopo Mondi 				.left	= 56,
7483145efcdSJacopo Mondi 				.top	= 60,
7493145efcdSJacopo Mondi 				.width	= 720,
7503145efcdSJacopo Mondi 				.height	= 480,
7513145efcdSJacopo Mondi 			},
7523145efcdSJacopo Mondi 			.htot		= 1896,
7533145efcdSJacopo Mondi 			.vblank_def	= 504,
7545113d5b3SJacopo Mondi 		},
7555113d5b3SJacopo Mondi 		.csi2_timings = {
7565113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
7575113d5b3SJacopo Mondi 			.analog_crop = {
7585113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
7595113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
7605113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
7615113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
7625113d5b3SJacopo Mondi 			},
7635113d5b3SJacopo Mondi 			.crop = {
7645113d5b3SJacopo Mondi 				.left	= 56,
7655113d5b3SJacopo Mondi 				.top	= 60,
7665113d5b3SJacopo Mondi 				.width	= 720,
7675113d5b3SJacopo Mondi 				.height	= 480,
7685113d5b3SJacopo Mondi 			},
7695113d5b3SJacopo Mondi 			.htot		= 1896,
7705113d5b3SJacopo Mondi 			.vblank_def	= 504,
7715113d5b3SJacopo Mondi 		},
772db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
773db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
7743145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
7758409d017SJacopo Mondi 	}, {
7768409d017SJacopo Mondi 		/* 720x576 */
7773145efcdSJacopo Mondi 		.id		= OV5640_MODE_PAL_720_576,
7783145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
7795113d5b3SJacopo Mondi 		.width		= 720,
7805113d5b3SJacopo Mondi 		.height		= 576,
7813145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
7825113d5b3SJacopo Mondi 		.dvp_timings = {
7833145efcdSJacopo Mondi 			.analog_crop = {
7843145efcdSJacopo Mondi 				.left	= 0,
7853145efcdSJacopo Mondi 				.top	= 4,
7863145efcdSJacopo Mondi 				.width	= 2624,
7873145efcdSJacopo Mondi 				.height	= 1944,
7883145efcdSJacopo Mondi 			},
7893145efcdSJacopo Mondi 			.crop = {
7903145efcdSJacopo Mondi 				.left	= 56,
7913145efcdSJacopo Mondi 				.top	= 6,
7923145efcdSJacopo Mondi 				.width	= 720,
7933145efcdSJacopo Mondi 				.height	= 576,
7943145efcdSJacopo Mondi 			},
7953145efcdSJacopo Mondi 			.htot		= 1896,
7963145efcdSJacopo Mondi 			.vblank_def	= 408,
7975113d5b3SJacopo Mondi 		},
7985113d5b3SJacopo Mondi 		.csi2_timings = {
7995113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
8005113d5b3SJacopo Mondi 			.analog_crop = {
8015113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
8025113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
8035113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
8045113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
8055113d5b3SJacopo Mondi 			},
8065113d5b3SJacopo Mondi 			.crop = {
8075113d5b3SJacopo Mondi 				.left	= 56,
8085113d5b3SJacopo Mondi 				.top	= 6,
8095113d5b3SJacopo Mondi 				.width	= 720,
8105113d5b3SJacopo Mondi 				.height	= 576,
8115113d5b3SJacopo Mondi 			},
8125113d5b3SJacopo Mondi 			.htot		= 1896,
8135113d5b3SJacopo Mondi 			.vblank_def	= 408,
8145113d5b3SJacopo Mondi 		},
815db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
816db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
8173145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
8188409d017SJacopo Mondi 	}, {
8198409d017SJacopo Mondi 		/* 1024x768 */
8203145efcdSJacopo Mondi 		.id		= OV5640_MODE_XGA_1024_768,
8213145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
8223145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
8235113d5b3SJacopo Mondi 		.width		= 1024,
8245113d5b3SJacopo Mondi 		.height		= 768,
8255113d5b3SJacopo Mondi 		.dvp_timings = {
8263145efcdSJacopo Mondi 			.analog_crop = {
8273145efcdSJacopo Mondi 				.left	= 0,
8283145efcdSJacopo Mondi 				.top	= 4,
8293145efcdSJacopo Mondi 				.width	= 2624,
8303145efcdSJacopo Mondi 				.height	= 1944,
8313145efcdSJacopo Mondi 			},
8323145efcdSJacopo Mondi 			.crop = {
8333145efcdSJacopo Mondi 				.left	= 16,
8343145efcdSJacopo Mondi 				.top	= 6,
8353145efcdSJacopo Mondi 				.width	= 1024,
8363145efcdSJacopo Mondi 				.height	= 768,
8373145efcdSJacopo Mondi 			},
8383145efcdSJacopo Mondi 			.htot		= 1896,
8393145efcdSJacopo Mondi 			.vblank_def	= 312,
8405113d5b3SJacopo Mondi 		},
8415113d5b3SJacopo Mondi 		.csi2_timings = {
8425113d5b3SJacopo Mondi 			.analog_crop = {
8435113d5b3SJacopo Mondi 				.left	= 0,
8445113d5b3SJacopo Mondi 				.top	= 4,
8455113d5b3SJacopo Mondi 				.width	= OV5640_NATIVE_WIDTH,
8465113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
8475113d5b3SJacopo Mondi 			},
8485113d5b3SJacopo Mondi 			.crop = {
8495113d5b3SJacopo Mondi 				.left	= 16,
8505113d5b3SJacopo Mondi 				.top	= 6,
8515113d5b3SJacopo Mondi 				.width	= 1024,
8525113d5b3SJacopo Mondi 				.height	= 768,
8535113d5b3SJacopo Mondi 			},
8545113d5b3SJacopo Mondi 			.htot		= 1896,
8555113d5b3SJacopo Mondi 			.vblank_def	= 312,
8565113d5b3SJacopo Mondi 		},
857db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
858db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
8593145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
8608409d017SJacopo Mondi 	}, {
8618409d017SJacopo Mondi 		/* 1280x720 */
8623145efcdSJacopo Mondi 		.id		= OV5640_MODE_720P_1280_720,
8633145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
8643145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_124M,
8655113d5b3SJacopo Mondi 		.width		= 1280,
8665113d5b3SJacopo Mondi 		.height		= 720,
8675113d5b3SJacopo Mondi 		.dvp_timings = {
8683145efcdSJacopo Mondi 			.analog_crop = {
8693145efcdSJacopo Mondi 				.left	= 0,
8703145efcdSJacopo Mondi 				.top	= 250,
8713145efcdSJacopo Mondi 				.width	= 2624,
8723145efcdSJacopo Mondi 				.height	= 1456,
8733145efcdSJacopo Mondi 			},
8743145efcdSJacopo Mondi 			.crop = {
8753145efcdSJacopo Mondi 				.left	= 16,
8763145efcdSJacopo Mondi 				.top	= 4,
8773145efcdSJacopo Mondi 				.width	= 1280,
8783145efcdSJacopo Mondi 				.height	= 720,
8793145efcdSJacopo Mondi 			},
8803145efcdSJacopo Mondi 			.htot		= 1892,
8813145efcdSJacopo Mondi 			.vblank_def	= 20,
8825113d5b3SJacopo Mondi 		},
8835113d5b3SJacopo Mondi 		.csi2_timings = {
8845113d5b3SJacopo Mondi 			.analog_crop = {
8855113d5b3SJacopo Mondi 				.left	= 0,
8865113d5b3SJacopo Mondi 				.top	= 250,
8875113d5b3SJacopo Mondi 				.width	= 2624,
8885113d5b3SJacopo Mondi 				.height	= 1456,
8895113d5b3SJacopo Mondi 			},
8905113d5b3SJacopo Mondi 			.crop = {
8915113d5b3SJacopo Mondi 				.left	= 16,
8925113d5b3SJacopo Mondi 				.top	= 4,
8935113d5b3SJacopo Mondi 				.width	= 1280,
8945113d5b3SJacopo Mondi 				.height	= 720,
8955113d5b3SJacopo Mondi 			},
8965113d5b3SJacopo Mondi 			.htot		= 1892,
8975113d5b3SJacopo Mondi 			.vblank_def	= 20,
8985113d5b3SJacopo Mondi 		},
8993145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_720P_1280_720,
9003145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_720P_1280_720),
9013145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
9028409d017SJacopo Mondi 	}, {
9038409d017SJacopo Mondi 		/* 1920x1080 */
9043145efcdSJacopo Mondi 		.id		= OV5640_MODE_1080P_1920_1080,
9053145efcdSJacopo Mondi 		.dn_mode	= SCALING,
9063145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_148M,
9075113d5b3SJacopo Mondi 		.width		= 1920,
9085113d5b3SJacopo Mondi 		.height		= 1080,
9095113d5b3SJacopo Mondi 		.dvp_timings = {
9103145efcdSJacopo Mondi 			.analog_crop = {
9113145efcdSJacopo Mondi 				.left	= 336,
9123145efcdSJacopo Mondi 				.top	= 434,
9133145efcdSJacopo Mondi 				.width	= 1952,
9143145efcdSJacopo Mondi 				.height	= 1088,
9153145efcdSJacopo Mondi 			},
9163145efcdSJacopo Mondi 			.crop = {
9173145efcdSJacopo Mondi 				.left	= 16,
9183145efcdSJacopo Mondi 				.top	= 4,
9193145efcdSJacopo Mondi 				.width	= 1920,
9203145efcdSJacopo Mondi 				.height	= 1080,
9213145efcdSJacopo Mondi 			},
9223145efcdSJacopo Mondi 			.htot		= 2500,
9233145efcdSJacopo Mondi 			.vblank_def	= 40,
9245113d5b3SJacopo Mondi 		},
9255113d5b3SJacopo Mondi 		.csi2_timings = {
9265113d5b3SJacopo Mondi 			/* Crop the full valid pixel array in the center. */
9275113d5b3SJacopo Mondi 			.analog_crop = {
9285113d5b3SJacopo Mondi 				.left	= 336,
9295113d5b3SJacopo Mondi 				.top	= 434,
9305113d5b3SJacopo Mondi 				.width	= 1952,
9315113d5b3SJacopo Mondi 				.height	= 1088,
9325113d5b3SJacopo Mondi 			},
9335113d5b3SJacopo Mondi 			/* Maintain a larger processing margins. */
9345113d5b3SJacopo Mondi 			.crop = {
9355113d5b3SJacopo Mondi 				.left	= 16,
9365113d5b3SJacopo Mondi 				.top	= 4,
9375113d5b3SJacopo Mondi 				.width	= 1920,
9385113d5b3SJacopo Mondi 				.height	= 1080,
9395113d5b3SJacopo Mondi 			},
9405113d5b3SJacopo Mondi 			.htot		= 2500,
9415113d5b3SJacopo Mondi 			.vblank_def	= 40,
9425113d5b3SJacopo Mondi 		},
9433145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_1080P_1920_1080,
9443145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_1080P_1920_1080),
9453145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
9468409d017SJacopo Mondi 	}, {
9478409d017SJacopo Mondi 		/* 2592x1944 */
9483145efcdSJacopo Mondi 		.id		= OV5640_MODE_QSXGA_2592_1944,
9493145efcdSJacopo Mondi 		.dn_mode	= SCALING,
9503145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_168M,
9515113d5b3SJacopo Mondi 		.width		= OV5640_PIXEL_ARRAY_WIDTH,
9525113d5b3SJacopo Mondi 		.height		= OV5640_PIXEL_ARRAY_HEIGHT,
9535113d5b3SJacopo Mondi 		.dvp_timings = {
9543145efcdSJacopo Mondi 			.analog_crop = {
9553145efcdSJacopo Mondi 				.left	= 0,
9563145efcdSJacopo Mondi 				.top	= 0,
9573145efcdSJacopo Mondi 				.width	= 2624,
9583145efcdSJacopo Mondi 				.height	= 1952,
9593145efcdSJacopo Mondi 			},
9603145efcdSJacopo Mondi 			.crop = {
9613145efcdSJacopo Mondi 				.left	= 16,
9623145efcdSJacopo Mondi 				.top	= 4,
9633145efcdSJacopo Mondi 				.width	= 2592,
9643145efcdSJacopo Mondi 				.height	= 1944,
9653145efcdSJacopo Mondi 			},
9663145efcdSJacopo Mondi 			.htot		= 2844,
9673145efcdSJacopo Mondi 			.vblank_def	= 24,
9685113d5b3SJacopo Mondi 		},
9695113d5b3SJacopo Mondi 		.csi2_timings = {
9705113d5b3SJacopo Mondi 			/* Give more processing margin to full resolution. */
9715113d5b3SJacopo Mondi 			.analog_crop = {
9725113d5b3SJacopo Mondi 				.left	= 0,
9735113d5b3SJacopo Mondi 				.top	= 0,
9745113d5b3SJacopo Mondi 				.width	= OV5640_NATIVE_WIDTH,
9755113d5b3SJacopo Mondi 				.height	= 1952,
9765113d5b3SJacopo Mondi 			},
9775113d5b3SJacopo Mondi 			.crop = {
9785113d5b3SJacopo Mondi 				.left	= 16,
9795113d5b3SJacopo Mondi 				.top	= 4,
9805113d5b3SJacopo Mondi 				.width	= 2592,
9815113d5b3SJacopo Mondi 				.height	= 1944,
9825113d5b3SJacopo Mondi 			},
9835113d5b3SJacopo Mondi 			.htot		= 2844,
9845113d5b3SJacopo Mondi 			.vblank_def	= 24,
9855113d5b3SJacopo Mondi 		},
9863145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_QSXGA_2592_1944,
9873145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_QSXGA_2592_1944),
9883145efcdSJacopo Mondi 		.max_fps	= OV5640_15_FPS
9898409d017SJacopo Mondi 	},
99019a81c14SSteve Longerbeam };
99119a81c14SSteve Longerbeam 
9922de6bb97SJacopo Mondi static const struct ov5640_timings *
9932de6bb97SJacopo Mondi ov5640_timings(const struct ov5640_dev *sensor,
9942de6bb97SJacopo Mondi 	       const struct ov5640_mode_info *mode)
9952de6bb97SJacopo Mondi {
9962de6bb97SJacopo Mondi 	if (ov5640_is_csi2(sensor))
9972de6bb97SJacopo Mondi 		return &mode->csi2_timings;
9982de6bb97SJacopo Mondi 
9992de6bb97SJacopo Mondi 	return &mode->dvp_timings;
10002de6bb97SJacopo Mondi }
10012de6bb97SJacopo Mondi 
100219a81c14SSteve Longerbeam static int ov5640_init_slave_id(struct ov5640_dev *sensor)
100319a81c14SSteve Longerbeam {
100419a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
100519a81c14SSteve Longerbeam 	struct i2c_msg msg;
100619a81c14SSteve Longerbeam 	u8 buf[3];
100719a81c14SSteve Longerbeam 	int ret;
100819a81c14SSteve Longerbeam 
100919a81c14SSteve Longerbeam 	if (client->addr == OV5640_DEFAULT_SLAVE_ID)
101019a81c14SSteve Longerbeam 		return 0;
101119a81c14SSteve Longerbeam 
101219a81c14SSteve Longerbeam 	buf[0] = OV5640_REG_SLAVE_ID >> 8;
101319a81c14SSteve Longerbeam 	buf[1] = OV5640_REG_SLAVE_ID & 0xff;
101419a81c14SSteve Longerbeam 	buf[2] = client->addr << 1;
101519a81c14SSteve Longerbeam 
101619a81c14SSteve Longerbeam 	msg.addr = OV5640_DEFAULT_SLAVE_ID;
101719a81c14SSteve Longerbeam 	msg.flags = 0;
101819a81c14SSteve Longerbeam 	msg.buf = buf;
101919a81c14SSteve Longerbeam 	msg.len = sizeof(buf);
102019a81c14SSteve Longerbeam 
102119a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, &msg, 1);
102219a81c14SSteve Longerbeam 	if (ret < 0) {
102319a81c14SSteve Longerbeam 		dev_err(&client->dev, "%s: failed with %d\n", __func__, ret);
102419a81c14SSteve Longerbeam 		return ret;
102519a81c14SSteve Longerbeam 	}
102619a81c14SSteve Longerbeam 
102719a81c14SSteve Longerbeam 	return 0;
102819a81c14SSteve Longerbeam }
102919a81c14SSteve Longerbeam 
103019a81c14SSteve Longerbeam static int ov5640_write_reg(struct ov5640_dev *sensor, u16 reg, u8 val)
103119a81c14SSteve Longerbeam {
103219a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
103319a81c14SSteve Longerbeam 	struct i2c_msg msg;
103419a81c14SSteve Longerbeam 	u8 buf[3];
103519a81c14SSteve Longerbeam 	int ret;
103619a81c14SSteve Longerbeam 
103719a81c14SSteve Longerbeam 	buf[0] = reg >> 8;
103819a81c14SSteve Longerbeam 	buf[1] = reg & 0xff;
103919a81c14SSteve Longerbeam 	buf[2] = val;
104019a81c14SSteve Longerbeam 
104119a81c14SSteve Longerbeam 	msg.addr = client->addr;
104219a81c14SSteve Longerbeam 	msg.flags = client->flags;
104319a81c14SSteve Longerbeam 	msg.buf = buf;
104419a81c14SSteve Longerbeam 	msg.len = sizeof(buf);
104519a81c14SSteve Longerbeam 
104619a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, &msg, 1);
104719a81c14SSteve Longerbeam 	if (ret < 0) {
10483924c623SHugues Fruchet 		dev_err(&client->dev, "%s: error: reg=%x, val=%x\n",
104919a81c14SSteve Longerbeam 			__func__, reg, val);
105019a81c14SSteve Longerbeam 		return ret;
105119a81c14SSteve Longerbeam 	}
105219a81c14SSteve Longerbeam 
105319a81c14SSteve Longerbeam 	return 0;
105419a81c14SSteve Longerbeam }
105519a81c14SSteve Longerbeam 
105619a81c14SSteve Longerbeam static int ov5640_read_reg(struct ov5640_dev *sensor, u16 reg, u8 *val)
105719a81c14SSteve Longerbeam {
105819a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
105919a81c14SSteve Longerbeam 	struct i2c_msg msg[2];
106019a81c14SSteve Longerbeam 	u8 buf[2];
106119a81c14SSteve Longerbeam 	int ret;
106219a81c14SSteve Longerbeam 
106319a81c14SSteve Longerbeam 	buf[0] = reg >> 8;
106419a81c14SSteve Longerbeam 	buf[1] = reg & 0xff;
106519a81c14SSteve Longerbeam 
106619a81c14SSteve Longerbeam 	msg[0].addr = client->addr;
106719a81c14SSteve Longerbeam 	msg[0].flags = client->flags;
106819a81c14SSteve Longerbeam 	msg[0].buf = buf;
106919a81c14SSteve Longerbeam 	msg[0].len = sizeof(buf);
107019a81c14SSteve Longerbeam 
107119a81c14SSteve Longerbeam 	msg[1].addr = client->addr;
107219a81c14SSteve Longerbeam 	msg[1].flags = client->flags | I2C_M_RD;
107319a81c14SSteve Longerbeam 	msg[1].buf = buf;
107419a81c14SSteve Longerbeam 	msg[1].len = 1;
107519a81c14SSteve Longerbeam 
107619a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, msg, 2);
10773924c623SHugues Fruchet 	if (ret < 0) {
10783924c623SHugues Fruchet 		dev_err(&client->dev, "%s: error: reg=%x\n",
10793924c623SHugues Fruchet 			__func__, reg);
108019a81c14SSteve Longerbeam 		return ret;
10813924c623SHugues Fruchet 	}
108219a81c14SSteve Longerbeam 
108319a81c14SSteve Longerbeam 	*val = buf[0];
108419a81c14SSteve Longerbeam 	return 0;
108519a81c14SSteve Longerbeam }
108619a81c14SSteve Longerbeam 
108719a81c14SSteve Longerbeam static int ov5640_read_reg16(struct ov5640_dev *sensor, u16 reg, u16 *val)
108819a81c14SSteve Longerbeam {
108919a81c14SSteve Longerbeam 	u8 hi, lo;
109019a81c14SSteve Longerbeam 	int ret;
109119a81c14SSteve Longerbeam 
109219a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg, &hi);
109319a81c14SSteve Longerbeam 	if (ret)
109419a81c14SSteve Longerbeam 		return ret;
109519a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg + 1, &lo);
109619a81c14SSteve Longerbeam 	if (ret)
109719a81c14SSteve Longerbeam 		return ret;
109819a81c14SSteve Longerbeam 
109919a81c14SSteve Longerbeam 	*val = ((u16)hi << 8) | (u16)lo;
110019a81c14SSteve Longerbeam 	return 0;
110119a81c14SSteve Longerbeam }
110219a81c14SSteve Longerbeam 
110319a81c14SSteve Longerbeam static int ov5640_write_reg16(struct ov5640_dev *sensor, u16 reg, u16 val)
110419a81c14SSteve Longerbeam {
110519a81c14SSteve Longerbeam 	int ret;
110619a81c14SSteve Longerbeam 
110719a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, reg, val >> 8);
110819a81c14SSteve Longerbeam 	if (ret)
110919a81c14SSteve Longerbeam 		return ret;
111019a81c14SSteve Longerbeam 
111119a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, reg + 1, val & 0xff);
111219a81c14SSteve Longerbeam }
111319a81c14SSteve Longerbeam 
111419a81c14SSteve Longerbeam static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg,
111519a81c14SSteve Longerbeam 			  u8 mask, u8 val)
111619a81c14SSteve Longerbeam {
111719a81c14SSteve Longerbeam 	u8 readval;
111819a81c14SSteve Longerbeam 	int ret;
111919a81c14SSteve Longerbeam 
112019a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg, &readval);
112119a81c14SSteve Longerbeam 	if (ret)
112219a81c14SSteve Longerbeam 		return ret;
112319a81c14SSteve Longerbeam 
112419a81c14SSteve Longerbeam 	readval &= ~mask;
112519a81c14SSteve Longerbeam 	val &= mask;
112619a81c14SSteve Longerbeam 	val |= readval;
112719a81c14SSteve Longerbeam 
112819a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, reg, val);
112919a81c14SSteve Longerbeam }
113019a81c14SSteve Longerbeam 
1131aa288248SMaxime Ripard /*
1132aa288248SMaxime Ripard  * After trying the various combinations, reading various
1133f8a7647dSMauro Carvalho Chehab  * documentations spread around the net, and from the various
1134aa288248SMaxime Ripard  * feedback, the clock tree is probably as follows:
1135aa288248SMaxime Ripard  *
1136aa288248SMaxime Ripard  *   +--------------+
1137aa288248SMaxime Ripard  *   |  Ext. Clock  |
1138aa288248SMaxime Ripard  *   +-+------------+
1139aa288248SMaxime Ripard  *     |  +----------+
1140aa288248SMaxime Ripard  *     +->|   PLL1   | - reg 0x3036, for the multiplier
1141aa288248SMaxime Ripard  *        +-+--------+ - reg 0x3037, bits 0-3 for the pre-divider
1142aa288248SMaxime Ripard  *          |  +--------------+
1143aa288248SMaxime Ripard  *          +->| System Clock |  - reg 0x3035, bits 4-7
1144aa288248SMaxime Ripard  *             +-+------------+
1145aa288248SMaxime Ripard  *               |  +--------------+
1146aa288248SMaxime Ripard  *               +->| MIPI Divider | - reg 0x3035, bits 0-3
1147aa288248SMaxime Ripard  *               |  +-+------------+
1148aa288248SMaxime Ripard  *               |    +----------------> MIPI SCLK
1149aa288248SMaxime Ripard  *               |    +  +-----+
1150aa288248SMaxime Ripard  *               |    +->| / 2 |-------> MIPI BIT CLK
1151aa288248SMaxime Ripard  *               |       +-----+
1152aa288248SMaxime Ripard  *               |  +--------------+
1153aa288248SMaxime Ripard  *               +->| PLL Root Div | - reg 0x3037, bit 4
1154aa288248SMaxime Ripard  *                  +-+------------+
1155aa288248SMaxime Ripard  *                    |  +---------+
11564c85f628SPaul Kocialkowski  *                    +->| Bit Div | - reg 0x3034, bits 0-3
1157aa288248SMaxime Ripard  *                       +-+-------+
1158aa288248SMaxime Ripard  *                         |  +-------------+
1159aa288248SMaxime Ripard  *                         +->| SCLK Div    | - reg 0x3108, bits 0-1
1160aa288248SMaxime Ripard  *                         |  +-+-----------+
1161aa288248SMaxime Ripard  *                         |    +---------------> SCLK
1162aa288248SMaxime Ripard  *                         |  +-------------+
1163aa288248SMaxime Ripard  *                         +->| SCLK 2X Div | - reg 0x3108, bits 2-3
1164aa288248SMaxime Ripard  *                         |  +-+-----------+
1165aa288248SMaxime Ripard  *                         |    +---------------> SCLK 2X
1166aa288248SMaxime Ripard  *                         |  +-------------+
1167aa288248SMaxime Ripard  *                         +->| PCLK Div    | - reg 0x3108, bits 4-5
1168aa288248SMaxime Ripard  *                            ++------------+
1169aa288248SMaxime Ripard  *                             +  +-----------+
1170aa288248SMaxime Ripard  *                             +->|   P_DIV   | - reg 0x3035, bits 0-3
1171aa288248SMaxime Ripard  *                                +-----+-----+
1172aa288248SMaxime Ripard  *                                       +------------> PCLK
1173aa288248SMaxime Ripard  *
11746c957ed7SJacopo Mondi  * There seems to be also constraints:
1175aa288248SMaxime Ripard  *  - the PLL pre-divider output rate should be in the 4-27MHz range
1176aa288248SMaxime Ripard  *  - the PLL multiplier output rate should be in the 500-1000MHz range
1177aa288248SMaxime Ripard  *  - PCLK >= SCLK * 2 in YUV, >= SCLK in Raw or JPEG
1178aa288248SMaxime Ripard  */
1179aa288248SMaxime Ripard 
1180aa288248SMaxime Ripard /*
1181aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1182aa288248SMaxime Ripard  * set to 3 in the vendor kernels.
1183aa288248SMaxime Ripard  */
1184aa288248SMaxime Ripard #define OV5640_PLL_PREDIV	3
1185aa288248SMaxime Ripard 
1186aa288248SMaxime Ripard #define OV5640_PLL_MULT_MIN	4
1187aa288248SMaxime Ripard #define OV5640_PLL_MULT_MAX	252
1188aa288248SMaxime Ripard 
1189aa288248SMaxime Ripard /*
1190aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 16, but the value is
1191aa288248SMaxime Ripard  * always set to either 1 or 2 in the vendor kernels.
1192aa288248SMaxime Ripard  */
1193aa288248SMaxime Ripard #define OV5640_SYSDIV_MIN	1
1194aa288248SMaxime Ripard #define OV5640_SYSDIV_MAX	16
1195aa288248SMaxime Ripard 
1196aa288248SMaxime Ripard /*
1197aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 2, but the value is always
1198aa288248SMaxime Ripard  * set to 2 in the vendor kernels.
1199aa288248SMaxime Ripard  */
1200aa288248SMaxime Ripard #define OV5640_PLL_ROOT_DIV			2
1201aa288248SMaxime Ripard #define OV5640_PLL_CTRL3_PLL_ROOT_DIV_2		BIT(4)
1202aa288248SMaxime Ripard 
1203aa288248SMaxime Ripard /*
1204aa288248SMaxime Ripard  * We only supports 8-bit formats at the moment
1205aa288248SMaxime Ripard  */
1206aa288248SMaxime Ripard #define OV5640_BIT_DIV				2
1207aa288248SMaxime Ripard #define OV5640_PLL_CTRL0_MIPI_MODE_8BIT		0x08
1208aa288248SMaxime Ripard 
1209aa288248SMaxime Ripard /*
1210aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1211aa288248SMaxime Ripard  * set to 2 in the vendor kernels.
1212aa288248SMaxime Ripard  */
1213aa288248SMaxime Ripard #define OV5640_SCLK_ROOT_DIV	2
1214aa288248SMaxime Ripard 
1215aa288248SMaxime Ripard /*
1216aa288248SMaxime Ripard  * This is hardcoded so that the consistency is maintained between SCLK and
1217aa288248SMaxime Ripard  * SCLK 2x.
1218aa288248SMaxime Ripard  */
1219aa288248SMaxime Ripard #define OV5640_SCLK2X_ROOT_DIV (OV5640_SCLK_ROOT_DIV / 2)
1220aa288248SMaxime Ripard 
1221aa288248SMaxime Ripard /*
1222aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1223aa288248SMaxime Ripard  * set to 1 in the vendor kernels.
1224aa288248SMaxime Ripard  */
1225aa288248SMaxime Ripard #define OV5640_PCLK_ROOT_DIV			1
1226aa288248SMaxime Ripard #define OV5640_PLL_SYS_ROOT_DIVIDER_BYPASS	0x00
1227aa288248SMaxime Ripard 
1228aa288248SMaxime Ripard static unsigned long ov5640_compute_sys_clk(struct ov5640_dev *sensor,
1229aa288248SMaxime Ripard 					    u8 pll_prediv, u8 pll_mult,
1230aa288248SMaxime Ripard 					    u8 sysdiv)
1231aa288248SMaxime Ripard {
1232aa288248SMaxime Ripard 	unsigned long sysclk = sensor->xclk_freq / pll_prediv * pll_mult;
1233aa288248SMaxime Ripard 
1234aa288248SMaxime Ripard 	/* PLL1 output cannot exceed 1GHz. */
1235aa288248SMaxime Ripard 	if (sysclk / 1000000 > 1000)
1236aa288248SMaxime Ripard 		return 0;
1237aa288248SMaxime Ripard 
1238aa288248SMaxime Ripard 	return sysclk / sysdiv;
1239aa288248SMaxime Ripard }
1240aa288248SMaxime Ripard 
1241aa288248SMaxime Ripard static unsigned long ov5640_calc_sys_clk(struct ov5640_dev *sensor,
1242aa288248SMaxime Ripard 					 unsigned long rate,
1243aa288248SMaxime Ripard 					 u8 *pll_prediv, u8 *pll_mult,
1244aa288248SMaxime Ripard 					 u8 *sysdiv)
1245aa288248SMaxime Ripard {
1246aa288248SMaxime Ripard 	unsigned long best = ~0;
1247aa288248SMaxime Ripard 	u8 best_sysdiv = 1, best_mult = 1;
1248aa288248SMaxime Ripard 	u8 _sysdiv, _pll_mult;
1249aa288248SMaxime Ripard 
1250aa288248SMaxime Ripard 	for (_sysdiv = OV5640_SYSDIV_MIN;
1251aa288248SMaxime Ripard 	     _sysdiv <= OV5640_SYSDIV_MAX;
1252aa288248SMaxime Ripard 	     _sysdiv++) {
1253aa288248SMaxime Ripard 		for (_pll_mult = OV5640_PLL_MULT_MIN;
1254aa288248SMaxime Ripard 		     _pll_mult <= OV5640_PLL_MULT_MAX;
1255aa288248SMaxime Ripard 		     _pll_mult++) {
1256aa288248SMaxime Ripard 			unsigned long _rate;
1257aa288248SMaxime Ripard 
1258aa288248SMaxime Ripard 			/*
1259aa288248SMaxime Ripard 			 * The PLL multiplier cannot be odd if above
1260aa288248SMaxime Ripard 			 * 127.
1261aa288248SMaxime Ripard 			 */
1262aa288248SMaxime Ripard 			if (_pll_mult > 127 && (_pll_mult % 2))
1263aa288248SMaxime Ripard 				continue;
1264aa288248SMaxime Ripard 
1265aa288248SMaxime Ripard 			_rate = ov5640_compute_sys_clk(sensor,
1266aa288248SMaxime Ripard 						       OV5640_PLL_PREDIV,
1267aa288248SMaxime Ripard 						       _pll_mult, _sysdiv);
1268aa288248SMaxime Ripard 
1269aa288248SMaxime Ripard 			/*
1270aa288248SMaxime Ripard 			 * We have reached the maximum allowed PLL1 output,
1271aa288248SMaxime Ripard 			 * increase sysdiv.
1272aa288248SMaxime Ripard 			 */
12732e3df204SAdam Ford 			if (!_rate)
1274aa288248SMaxime Ripard 				break;
1275aa288248SMaxime Ripard 
1276aa288248SMaxime Ripard 			/*
1277aa288248SMaxime Ripard 			 * Prefer rates above the expected clock rate than
1278aa288248SMaxime Ripard 			 * below, even if that means being less precise.
1279aa288248SMaxime Ripard 			 */
1280aa288248SMaxime Ripard 			if (_rate < rate)
1281aa288248SMaxime Ripard 				continue;
1282aa288248SMaxime Ripard 
1283aa288248SMaxime Ripard 			if (abs(rate - _rate) < abs(rate - best)) {
1284aa288248SMaxime Ripard 				best = _rate;
1285aa288248SMaxime Ripard 				best_sysdiv = _sysdiv;
1286aa288248SMaxime Ripard 				best_mult = _pll_mult;
1287aa288248SMaxime Ripard 			}
1288aa288248SMaxime Ripard 
1289aa288248SMaxime Ripard 			if (_rate == rate)
1290aa288248SMaxime Ripard 				goto out;
1291aa288248SMaxime Ripard 		}
1292aa288248SMaxime Ripard 	}
1293aa288248SMaxime Ripard 
1294aa288248SMaxime Ripard out:
1295aa288248SMaxime Ripard 	*sysdiv = best_sysdiv;
1296aa288248SMaxime Ripard 	*pll_prediv = OV5640_PLL_PREDIV;
1297aa288248SMaxime Ripard 	*pll_mult = best_mult;
1298aa288248SMaxime Ripard 
1299aa288248SMaxime Ripard 	return best;
1300aa288248SMaxime Ripard }
1301aa288248SMaxime Ripard 
1302aa288248SMaxime Ripard /*
1303aa288248SMaxime Ripard  * ov5640_set_mipi_pclk() - Calculate the clock tree configuration values
1304aa288248SMaxime Ripard  *			    for the MIPI CSI-2 output.
1305aa288248SMaxime Ripard  */
13066c957ed7SJacopo Mondi static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor)
1307aa288248SMaxime Ripard {
13086c957ed7SJacopo Mondi 	u8 bit_div, mipi_div, pclk_div, sclk_div, sclk2x_div, root_div;
1309aa288248SMaxime Ripard 	u8 prediv, mult, sysdiv;
13106c957ed7SJacopo Mondi 	unsigned long link_freq;
13116c957ed7SJacopo Mondi 	unsigned long sysclk;
13126c957ed7SJacopo Mondi 	u8 pclk_period;
13136c957ed7SJacopo Mondi 	u32 sample_rate;
13146c957ed7SJacopo Mondi 	u32 num_lanes;
1315aa288248SMaxime Ripard 	int ret;
1316aa288248SMaxime Ripard 
13176c957ed7SJacopo Mondi 	/* Use the link freq computed at ov5640_update_pixel_rate() time. */
13186c957ed7SJacopo Mondi 	link_freq = sensor->current_link_freq;
13196c957ed7SJacopo Mondi 
1320aa288248SMaxime Ripard 	/*
13216c957ed7SJacopo Mondi 	 * - mipi_div - Additional divider for the MIPI lane clock.
13226c957ed7SJacopo Mondi 	 *
13236c957ed7SJacopo Mondi 	 * Higher link frequencies would make sysclk > 1GHz.
13246c957ed7SJacopo Mondi 	 * Keep the sysclk low and do not divide in the MIPI domain.
1325aa288248SMaxime Ripard 	 */
13266c957ed7SJacopo Mondi 	if (link_freq > OV5640_LINK_RATE_MAX)
13276c957ed7SJacopo Mondi 		mipi_div = 1;
1328aa288248SMaxime Ripard 	else
13296c957ed7SJacopo Mondi 		mipi_div = 2;
1330aa288248SMaxime Ripard 
13316c957ed7SJacopo Mondi 	sysclk = link_freq * mipi_div;
13326c957ed7SJacopo Mondi 	ov5640_calc_sys_clk(sensor, sysclk, &prediv, &mult, &sysdiv);
1333aa288248SMaxime Ripard 
13346c957ed7SJacopo Mondi 	/*
13356c957ed7SJacopo Mondi 	 * Adjust PLL parameters to maintain the MIPI_SCLK-to-PCLK ratio.
13366c957ed7SJacopo Mondi 	 *
13376c957ed7SJacopo Mondi 	 * - root_div = 2 (fixed)
13386c957ed7SJacopo Mondi 	 * - bit_div : MIPI 8-bit = 2; MIPI 10-bit = 2.5
13396c957ed7SJacopo Mondi 	 * - pclk_div = 1 (fixed)
13406c957ed7SJacopo Mondi 	 * - p_div  = (2 lanes ? mipi_div : 2 * mipi_div)
13416c957ed7SJacopo Mondi 	 *
13426c957ed7SJacopo Mondi 	 * This results in the following MIPI_SCLK depending on the number
13436c957ed7SJacopo Mondi 	 * of lanes:
13446c957ed7SJacopo Mondi 	 *
13456c957ed7SJacopo Mondi 	 * - 2 lanes: MIPI_SCLK = (4 or 5) * PCLK
13466c957ed7SJacopo Mondi 	 * - 1 lanes: MIPI_SCLK = (8 or 10) * PCLK
13476c957ed7SJacopo Mondi 	 */
13486c957ed7SJacopo Mondi 	root_div = OV5640_PLL_CTRL3_PLL_ROOT_DIV_2;
13496c957ed7SJacopo Mondi 	bit_div =  OV5640_PLL_CTRL0_MIPI_MODE_8BIT;
13506c957ed7SJacopo Mondi 	pclk_div = ilog2(OV5640_PCLK_ROOT_DIV);
1351aa288248SMaxime Ripard 
13526c957ed7SJacopo Mondi 	/*
13536c957ed7SJacopo Mondi 	 * Scaler clock:
13546c957ed7SJacopo Mondi 	 * - YUV: PCLK >= 2 * SCLK
13556c957ed7SJacopo Mondi 	 * - RAW or JPEG: PCLK >= SCLK
13566c957ed7SJacopo Mondi 	 * - sclk2x_div = sclk_div / 2
13576c957ed7SJacopo Mondi 	 */
13586c957ed7SJacopo Mondi 	sclk_div = ilog2(OV5640_SCLK_ROOT_DIV);
13596c957ed7SJacopo Mondi 	sclk2x_div = ilog2(OV5640_SCLK2X_ROOT_DIV);
13606c957ed7SJacopo Mondi 
13616c957ed7SJacopo Mondi 	/*
13626c957ed7SJacopo Mondi 	 * Set the pixel clock period expressed in ns with 1-bit decimal
13636c957ed7SJacopo Mondi 	 * (0x01=0.5ns).
13646c957ed7SJacopo Mondi 	 *
13656c957ed7SJacopo Mondi 	 * The register is very briefly documented. In the OV5645 datasheet it
13666c957ed7SJacopo Mondi 	 * is described as (2 * pclk period), and from testing it seems the
13676c957ed7SJacopo Mondi 	 * actual definition is 2 * 8-bit sample period.
13686c957ed7SJacopo Mondi 	 *
13696c957ed7SJacopo Mondi 	 * 2 * sample_period = (mipi_clk * 2 * num_lanes / bpp) * (bpp / 8) / 2
13706c957ed7SJacopo Mondi 	 */
13716c957ed7SJacopo Mondi 	num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes;
13726c957ed7SJacopo Mondi 	sample_rate = (link_freq * mipi_div * num_lanes * 2) / 16;
13736c957ed7SJacopo Mondi 	pclk_period = 2000000000UL / sample_rate;
13746c957ed7SJacopo Mondi 
13756c957ed7SJacopo Mondi 	/* Program the clock tree registers. */
13766c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0, 0x0f, bit_div);
13776c957ed7SJacopo Mondi 	if (ret)
13786c957ed7SJacopo Mondi 		return ret;
13796c957ed7SJacopo Mondi 
13806c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, 0xff,
13816c957ed7SJacopo Mondi 			     (sysdiv << 4) | mipi_div);
1382aa288248SMaxime Ripard 	if (ret)
1383aa288248SMaxime Ripard 		return ret;
1384aa288248SMaxime Ripard 
1385aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2, 0xff, mult);
1386aa288248SMaxime Ripard 	if (ret)
1387aa288248SMaxime Ripard 		return ret;
1388aa288248SMaxime Ripard 
13896c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3, 0x1f,
13906c957ed7SJacopo Mondi 			     root_div | prediv);
1391aa288248SMaxime Ripard 	if (ret)
1392aa288248SMaxime Ripard 		return ret;
1393aa288248SMaxime Ripard 
13946c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
13956c957ed7SJacopo Mondi 			     (pclk_div << 4) | (sclk2x_div << 2) | sclk_div);
13966c957ed7SJacopo Mondi 	if (ret)
13976c957ed7SJacopo Mondi 		return ret;
13986c957ed7SJacopo Mondi 
13996c957ed7SJacopo Mondi 	return ov5640_write_reg(sensor, OV5640_REG_PCLK_PERIOD, pclk_period);
14006c957ed7SJacopo Mondi }
14016c957ed7SJacopo Mondi 
14026c957ed7SJacopo Mondi static u32 ov5640_calc_pixel_rate(struct ov5640_dev *sensor)
14036c957ed7SJacopo Mondi {
14043145efcdSJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
14055113d5b3SJacopo Mondi 	const struct ov5640_timings *timings = &mode->dvp_timings;
14066c957ed7SJacopo Mondi 	u32 rate;
14076c957ed7SJacopo Mondi 
14085113d5b3SJacopo Mondi 	rate = timings->htot * (timings->crop.height + timings->vblank_def);
14096c957ed7SJacopo Mondi 	rate *= ov5640_framerates[sensor->current_fr];
14106c957ed7SJacopo Mondi 
14116c957ed7SJacopo Mondi 	return rate;
1412aa288248SMaxime Ripard }
1413aa288248SMaxime Ripard 
1414aa288248SMaxime Ripard static unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor,
1415aa288248SMaxime Ripard 				      unsigned long rate,
1416aa288248SMaxime Ripard 				      u8 *pll_prediv, u8 *pll_mult, u8 *sysdiv,
1417aa288248SMaxime Ripard 				      u8 *pll_rdiv, u8 *bit_div, u8 *pclk_div)
1418aa288248SMaxime Ripard {
1419aa288248SMaxime Ripard 	unsigned long _rate = rate * OV5640_PLL_ROOT_DIV * OV5640_BIT_DIV *
1420aa288248SMaxime Ripard 				OV5640_PCLK_ROOT_DIV;
1421aa288248SMaxime Ripard 
1422aa288248SMaxime Ripard 	_rate = ov5640_calc_sys_clk(sensor, _rate, pll_prediv, pll_mult,
1423aa288248SMaxime Ripard 				    sysdiv);
1424aa288248SMaxime Ripard 	*pll_rdiv = OV5640_PLL_ROOT_DIV;
1425aa288248SMaxime Ripard 	*bit_div = OV5640_BIT_DIV;
1426aa288248SMaxime Ripard 	*pclk_div = OV5640_PCLK_ROOT_DIV;
1427aa288248SMaxime Ripard 
1428aa288248SMaxime Ripard 	return _rate / *pll_rdiv / *bit_div / *pclk_div;
1429aa288248SMaxime Ripard }
1430aa288248SMaxime Ripard 
14316c957ed7SJacopo Mondi static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor)
1432aa288248SMaxime Ripard {
1433aa288248SMaxime Ripard 	u8 prediv, mult, sysdiv, pll_rdiv, bit_div, pclk_div;
14346c957ed7SJacopo Mondi 	u32 rate;
1435aa288248SMaxime Ripard 	int ret;
1436aa288248SMaxime Ripard 
14376c957ed7SJacopo Mondi 	rate = ov5640_calc_pixel_rate(sensor);
14386c957ed7SJacopo Mondi 	rate *= ov5640_code_to_bpp(sensor->fmt.code);
14396c957ed7SJacopo Mondi 	rate /= sensor->ep.bus.parallel.bus_width;
14406c957ed7SJacopo Mondi 
1441aa288248SMaxime Ripard 	ov5640_calc_pclk(sensor, rate, &prediv, &mult, &sysdiv, &pll_rdiv,
1442aa288248SMaxime Ripard 			 &bit_div, &pclk_div);
1443aa288248SMaxime Ripard 
1444aa288248SMaxime Ripard 	if (bit_div == 2)
1445aa288248SMaxime Ripard 		bit_div = 8;
1446aa288248SMaxime Ripard 
1447aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0,
1448aa288248SMaxime Ripard 			     0x0f, bit_div);
1449aa288248SMaxime Ripard 	if (ret)
1450aa288248SMaxime Ripard 		return ret;
1451aa288248SMaxime Ripard 
1452aa288248SMaxime Ripard 	/*
1453aa288248SMaxime Ripard 	 * We need to set sysdiv according to the clock, and to clear
1454aa288248SMaxime Ripard 	 * the MIPI divider.
1455aa288248SMaxime Ripard 	 */
1456aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1,
1457aa288248SMaxime Ripard 			     0xff, sysdiv << 4);
1458aa288248SMaxime Ripard 	if (ret)
1459aa288248SMaxime Ripard 		return ret;
1460aa288248SMaxime Ripard 
1461aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2,
1462aa288248SMaxime Ripard 			     0xff, mult);
1463aa288248SMaxime Ripard 	if (ret)
1464aa288248SMaxime Ripard 		return ret;
1465aa288248SMaxime Ripard 
1466aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3,
1467aa288248SMaxime Ripard 			     0x1f, prediv | ((pll_rdiv - 1) << 4));
1468aa288248SMaxime Ripard 	if (ret)
1469aa288248SMaxime Ripard 		return ret;
1470aa288248SMaxime Ripard 
1471aa288248SMaxime Ripard 	return ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x30,
1472aa288248SMaxime Ripard 			      (ilog2(pclk_div) << 4));
1473aa288248SMaxime Ripard }
1474aa288248SMaxime Ripard 
14757cb013b1SChen-Yu Tsai /* set JPEG framing sizes */
14767cb013b1SChen-Yu Tsai static int ov5640_set_jpeg_timings(struct ov5640_dev *sensor,
14777cb013b1SChen-Yu Tsai 				   const struct ov5640_mode_info *mode)
14787cb013b1SChen-Yu Tsai {
14797cb013b1SChen-Yu Tsai 	int ret;
14807cb013b1SChen-Yu Tsai 
14812b5c18f9SChen-Yu Tsai 	/*
14822b5c18f9SChen-Yu Tsai 	 * compression mode 3 timing
14832b5c18f9SChen-Yu Tsai 	 *
14842b5c18f9SChen-Yu Tsai 	 * Data is transmitted with programmable width (VFIFO_HSIZE).
14852b5c18f9SChen-Yu Tsai 	 * No padding done. Last line may have less data. Varying
14862b5c18f9SChen-Yu Tsai 	 * number of lines per frame, depending on amount of data.
14872b5c18f9SChen-Yu Tsai 	 */
14882b5c18f9SChen-Yu Tsai 	ret = ov5640_mod_reg(sensor, OV5640_REG_JPG_MODE_SELECT, 0x7, 0x3);
14892b5c18f9SChen-Yu Tsai 	if (ret < 0)
14902b5c18f9SChen-Yu Tsai 		return ret;
14912b5c18f9SChen-Yu Tsai 
14925113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_VFIFO_HSIZE, mode->width);
14937cb013b1SChen-Yu Tsai 	if (ret < 0)
14947cb013b1SChen-Yu Tsai 		return ret;
14957cb013b1SChen-Yu Tsai 
14965113d5b3SJacopo Mondi 	return ov5640_write_reg16(sensor, OV5640_REG_VFIFO_VSIZE, mode->height);
14977cb013b1SChen-Yu Tsai }
14987cb013b1SChen-Yu Tsai 
149919a81c14SSteve Longerbeam /* download ov5640 settings to sensor through i2c */
1500bad1774eSJacopo Mondi static int ov5640_set_timings(struct ov5640_dev *sensor,
1501bad1774eSJacopo Mondi 			      const struct ov5640_mode_info *mode)
1502bad1774eSJacopo Mondi {
15035113d5b3SJacopo Mondi 	const struct ov5640_timings *timings;
15045113d5b3SJacopo Mondi 	const struct v4l2_rect *analog_crop;
15055113d5b3SJacopo Mondi 	const struct v4l2_rect *crop;
1506bad1774eSJacopo Mondi 	int ret;
1507bad1774eSJacopo Mondi 
15087cb013b1SChen-Yu Tsai 	if (sensor->fmt.code == MEDIA_BUS_FMT_JPEG_1X8) {
15097cb013b1SChen-Yu Tsai 		ret = ov5640_set_jpeg_timings(sensor, mode);
15107cb013b1SChen-Yu Tsai 		if (ret < 0)
15117cb013b1SChen-Yu Tsai 			return ret;
15127cb013b1SChen-Yu Tsai 	}
15137cb013b1SChen-Yu Tsai 
15142de6bb97SJacopo Mondi 	timings = ov5640_timings(sensor, mode);
15155113d5b3SJacopo Mondi 	analog_crop = &timings->analog_crop;
15165113d5b3SJacopo Mondi 	crop = &timings->crop;
15175113d5b3SJacopo Mondi 
15183145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HS,
15193145efcdSJacopo Mondi 				 analog_crop->left);
1520bad1774eSJacopo Mondi 	if (ret < 0)
1521bad1774eSJacopo Mondi 		return ret;
1522bad1774eSJacopo Mondi 
15233145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VS,
15243145efcdSJacopo Mondi 				 analog_crop->top);
15253145efcdSJacopo Mondi 	if (ret < 0)
15263145efcdSJacopo Mondi 		return ret;
15273145efcdSJacopo Mondi 
15283145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HW,
15293145efcdSJacopo Mondi 				 analog_crop->left + analog_crop->width - 1);
15303145efcdSJacopo Mondi 	if (ret < 0)
15313145efcdSJacopo Mondi 		return ret;
15323145efcdSJacopo Mondi 
15333145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VH,
15343145efcdSJacopo Mondi 				 analog_crop->top + analog_crop->height - 1);
15353145efcdSJacopo Mondi 	if (ret < 0)
15363145efcdSJacopo Mondi 		return ret;
15373145efcdSJacopo Mondi 
15383145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HOFFS, crop->left);
15393145efcdSJacopo Mondi 	if (ret < 0)
15403145efcdSJacopo Mondi 		return ret;
15413145efcdSJacopo Mondi 
15423145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VOFFS, crop->top);
15433145efcdSJacopo Mondi 	if (ret < 0)
15443145efcdSJacopo Mondi 		return ret;
15453145efcdSJacopo Mondi 
15465113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->width);
15473145efcdSJacopo Mondi 	if (ret < 0)
15483145efcdSJacopo Mondi 		return ret;
15493145efcdSJacopo Mondi 
15505113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, mode->height);
1551bad1774eSJacopo Mondi 	if (ret < 0)
1552bad1774eSJacopo Mondi 		return ret;
1553bad1774eSJacopo Mondi 
15545113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, timings->htot);
1555bad1774eSJacopo Mondi 	if (ret < 0)
1556bad1774eSJacopo Mondi 		return ret;
1557bad1774eSJacopo Mondi 
15583145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS,
15595113d5b3SJacopo Mondi 				 mode->height + timings->vblank_def);
15603145efcdSJacopo Mondi 	if (ret < 0)
15613145efcdSJacopo Mondi 		return ret;
15623145efcdSJacopo Mondi 
15633145efcdSJacopo Mondi 	return 0;
1564bad1774eSJacopo Mondi }
1565bad1774eSJacopo Mondi 
1566*e4359019SJacopo Mondi static void ov5640_load_regs(struct ov5640_dev *sensor,
1567*e4359019SJacopo Mondi 			     const struct reg_value *regs, unsigned int regnum)
156819a81c14SSteve Longerbeam {
156919a81c14SSteve Longerbeam 	unsigned int i;
157019a81c14SSteve Longerbeam 	u32 delay_ms;
157119a81c14SSteve Longerbeam 	u16 reg_addr;
157219a81c14SSteve Longerbeam 	u8 mask, val;
157319a81c14SSteve Longerbeam 	int ret = 0;
157419a81c14SSteve Longerbeam 
1575*e4359019SJacopo Mondi 	for (i = 0; i < regnum; ++i, ++regs) {
157619a81c14SSteve Longerbeam 		delay_ms = regs->delay_ms;
157719a81c14SSteve Longerbeam 		reg_addr = regs->reg_addr;
157819a81c14SSteve Longerbeam 		val = regs->val;
157919a81c14SSteve Longerbeam 		mask = regs->mask;
158019a81c14SSteve Longerbeam 
15813b987d70SLad Prabhakar 		/* remain in power down mode for DVP */
15823b987d70SLad Prabhakar 		if (regs->reg_addr == OV5640_REG_SYS_CTRL0 &&
15833b987d70SLad Prabhakar 		    val == OV5640_REG_SYS_CTRL0_SW_PWUP &&
15848e823f5cSJacopo Mondi 		    !ov5640_is_csi2(sensor))
15853b987d70SLad Prabhakar 			continue;
15863b987d70SLad Prabhakar 
158719a81c14SSteve Longerbeam 		if (mask)
158819a81c14SSteve Longerbeam 			ret = ov5640_mod_reg(sensor, reg_addr, mask, val);
158919a81c14SSteve Longerbeam 		else
159019a81c14SSteve Longerbeam 			ret = ov5640_write_reg(sensor, reg_addr, val);
159119a81c14SSteve Longerbeam 		if (ret)
159219a81c14SSteve Longerbeam 			break;
159319a81c14SSteve Longerbeam 
159419a81c14SSteve Longerbeam 		if (delay_ms)
159519a81c14SSteve Longerbeam 			usleep_range(1000 * delay_ms, 1000 * delay_ms + 100);
159619a81c14SSteve Longerbeam 	}
159719a81c14SSteve Longerbeam }
159819a81c14SSteve Longerbeam 
1599dc29a1c1SHugues Fruchet static int ov5640_set_autoexposure(struct ov5640_dev *sensor, bool on)
1600dc29a1c1SHugues Fruchet {
1601dc29a1c1SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
1602dc29a1c1SHugues Fruchet 			      BIT(0), on ? 0 : BIT(0));
1603dc29a1c1SHugues Fruchet }
1604dc29a1c1SHugues Fruchet 
160519a81c14SSteve Longerbeam /* read exposure, in number of line periods */
160619a81c14SSteve Longerbeam static int ov5640_get_exposure(struct ov5640_dev *sensor)
160719a81c14SSteve Longerbeam {
160819a81c14SSteve Longerbeam 	int exp, ret;
160919a81c14SSteve Longerbeam 	u8 temp;
161019a81c14SSteve Longerbeam 
161119a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_HI, &temp);
161219a81c14SSteve Longerbeam 	if (ret)
161319a81c14SSteve Longerbeam 		return ret;
161419a81c14SSteve Longerbeam 	exp = ((int)temp & 0x0f) << 16;
161519a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_MED, &temp);
161619a81c14SSteve Longerbeam 	if (ret)
161719a81c14SSteve Longerbeam 		return ret;
161819a81c14SSteve Longerbeam 	exp |= ((int)temp << 8);
161919a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_LO, &temp);
162019a81c14SSteve Longerbeam 	if (ret)
162119a81c14SSteve Longerbeam 		return ret;
162219a81c14SSteve Longerbeam 	exp |= (int)temp;
162319a81c14SSteve Longerbeam 
162419a81c14SSteve Longerbeam 	return exp >> 4;
162519a81c14SSteve Longerbeam }
162619a81c14SSteve Longerbeam 
162719a81c14SSteve Longerbeam /* write exposure, given number of line periods */
162819a81c14SSteve Longerbeam static int ov5640_set_exposure(struct ov5640_dev *sensor, u32 exposure)
162919a81c14SSteve Longerbeam {
163019a81c14SSteve Longerbeam 	int ret;
163119a81c14SSteve Longerbeam 
163219a81c14SSteve Longerbeam 	exposure <<= 4;
163319a81c14SSteve Longerbeam 
163419a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor,
163519a81c14SSteve Longerbeam 			       OV5640_REG_AEC_PK_EXPOSURE_LO,
163619a81c14SSteve Longerbeam 			       exposure & 0xff);
163719a81c14SSteve Longerbeam 	if (ret)
163819a81c14SSteve Longerbeam 		return ret;
163919a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor,
164019a81c14SSteve Longerbeam 			       OV5640_REG_AEC_PK_EXPOSURE_MED,
164119a81c14SSteve Longerbeam 			       (exposure >> 8) & 0xff);
164219a81c14SSteve Longerbeam 	if (ret)
164319a81c14SSteve Longerbeam 		return ret;
164419a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor,
164519a81c14SSteve Longerbeam 				OV5640_REG_AEC_PK_EXPOSURE_HI,
164619a81c14SSteve Longerbeam 				(exposure >> 16) & 0x0f);
164719a81c14SSteve Longerbeam }
164819a81c14SSteve Longerbeam 
164919a81c14SSteve Longerbeam static int ov5640_get_gain(struct ov5640_dev *sensor)
165019a81c14SSteve Longerbeam {
165119a81c14SSteve Longerbeam 	u16 gain;
165219a81c14SSteve Longerbeam 	int ret;
165319a81c14SSteve Longerbeam 
165419a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN, &gain);
165519a81c14SSteve Longerbeam 	if (ret)
165619a81c14SSteve Longerbeam 		return ret;
165719a81c14SSteve Longerbeam 
165819a81c14SSteve Longerbeam 	return gain & 0x3ff;
165919a81c14SSteve Longerbeam }
166019a81c14SSteve Longerbeam 
16613cca8ef5SHugues Fruchet static int ov5640_set_gain(struct ov5640_dev *sensor, int gain)
16623cca8ef5SHugues Fruchet {
16633cca8ef5SHugues Fruchet 	return ov5640_write_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN,
16643cca8ef5SHugues Fruchet 				  (u16)gain & 0x3ff);
16653cca8ef5SHugues Fruchet }
16663cca8ef5SHugues Fruchet 
16673cca8ef5SHugues Fruchet static int ov5640_set_autogain(struct ov5640_dev *sensor, bool on)
16683cca8ef5SHugues Fruchet {
16693cca8ef5SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
16703cca8ef5SHugues Fruchet 			      BIT(1), on ? 0 : BIT(1));
16713cca8ef5SHugues Fruchet }
16723cca8ef5SHugues Fruchet 
1673f22996dbSHugues Fruchet static int ov5640_set_stream_dvp(struct ov5640_dev *sensor, bool on)
1674f22996dbSHugues Fruchet {
16753b987d70SLad Prabhakar 	return ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0, on ?
16763b987d70SLad Prabhakar 				OV5640_REG_SYS_CTRL0_SW_PWUP :
16773b987d70SLad Prabhakar 				OV5640_REG_SYS_CTRL0_SW_PWDN);
1678f22996dbSHugues Fruchet }
1679f22996dbSHugues Fruchet 
1680f22996dbSHugues Fruchet static int ov5640_set_stream_mipi(struct ov5640_dev *sensor, bool on)
168119a81c14SSteve Longerbeam {
168219a81c14SSteve Longerbeam 	int ret;
168319a81c14SSteve Longerbeam 
1684aa4bb8b8SJacopo Mondi 	/*
1685aa4bb8b8SJacopo Mondi 	 * Enable/disable the MIPI interface
1686aa4bb8b8SJacopo Mondi 	 *
1687aa4bb8b8SJacopo Mondi 	 * 0x300e = on ? 0x45 : 0x40
1688aa4bb8b8SJacopo Mondi 	 *
1689aa4bb8b8SJacopo Mondi 	 * FIXME: the sensor manual (version 2.03) reports
1690aa4bb8b8SJacopo Mondi 	 * [7:5] = 000  : 1 data lane mode
1691aa4bb8b8SJacopo Mondi 	 * [7:5] = 001  : 2 data lanes mode
1692aa4bb8b8SJacopo Mondi 	 * But this settings do not work, while the following ones
1693aa4bb8b8SJacopo Mondi 	 * have been validated for 2 data lanes mode.
1694aa4bb8b8SJacopo Mondi 	 *
1695aa4bb8b8SJacopo Mondi 	 * [7:5] = 010	: 2 data lanes mode
1696aa4bb8b8SJacopo Mondi 	 * [4] = 0	: Power up MIPI HS Tx
1697aa4bb8b8SJacopo Mondi 	 * [3] = 0	: Power up MIPI LS Rx
1698aa4bb8b8SJacopo Mondi 	 * [2] = 1/0	: MIPI interface enable/disable
1699aa4bb8b8SJacopo Mondi 	 * [1:0] = 01/00: FIXME: 'debug'
1700aa4bb8b8SJacopo Mondi 	 */
1701aa4bb8b8SJacopo Mondi 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00,
1702aa4bb8b8SJacopo Mondi 			       on ? 0x45 : 0x40);
170319a81c14SSteve Longerbeam 	if (ret)
170419a81c14SSteve Longerbeam 		return ret;
170519a81c14SSteve Longerbeam 
170619a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_FRAME_CTRL01,
170719a81c14SSteve Longerbeam 				on ? 0x00 : 0x0f);
170819a81c14SSteve Longerbeam }
170919a81c14SSteve Longerbeam 
171019a81c14SSteve Longerbeam static int ov5640_get_sysclk(struct ov5640_dev *sensor)
171119a81c14SSteve Longerbeam {
171219a81c14SSteve Longerbeam 	 /* calculate sysclk */
171319a81c14SSteve Longerbeam 	u32 xvclk = sensor->xclk_freq / 10000;
171419a81c14SSteve Longerbeam 	u32 multiplier, prediv, VCO, sysdiv, pll_rdiv;
171519a81c14SSteve Longerbeam 	u32 sclk_rdiv_map[] = {1, 2, 4, 8};
171619a81c14SSteve Longerbeam 	u32 bit_div2x = 1, sclk_rdiv, sysclk;
171719a81c14SSteve Longerbeam 	u8 temp1, temp2;
171819a81c14SSteve Longerbeam 	int ret;
171919a81c14SSteve Longerbeam 
172019a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL0, &temp1);
172119a81c14SSteve Longerbeam 	if (ret)
172219a81c14SSteve Longerbeam 		return ret;
172319a81c14SSteve Longerbeam 	temp2 = temp1 & 0x0f;
172419a81c14SSteve Longerbeam 	if (temp2 == 8 || temp2 == 10)
172519a81c14SSteve Longerbeam 		bit_div2x = temp2 / 2;
172619a81c14SSteve Longerbeam 
172719a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL1, &temp1);
172819a81c14SSteve Longerbeam 	if (ret)
172919a81c14SSteve Longerbeam 		return ret;
173019a81c14SSteve Longerbeam 	sysdiv = temp1 >> 4;
173119a81c14SSteve Longerbeam 	if (sysdiv == 0)
173219a81c14SSteve Longerbeam 		sysdiv = 16;
173319a81c14SSteve Longerbeam 
173419a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL2, &temp1);
173519a81c14SSteve Longerbeam 	if (ret)
173619a81c14SSteve Longerbeam 		return ret;
173719a81c14SSteve Longerbeam 	multiplier = temp1;
173819a81c14SSteve Longerbeam 
173919a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL3, &temp1);
174019a81c14SSteve Longerbeam 	if (ret)
174119a81c14SSteve Longerbeam 		return ret;
174219a81c14SSteve Longerbeam 	prediv = temp1 & 0x0f;
174319a81c14SSteve Longerbeam 	pll_rdiv = ((temp1 >> 4) & 0x01) + 1;
174419a81c14SSteve Longerbeam 
174519a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, &temp1);
174619a81c14SSteve Longerbeam 	if (ret)
174719a81c14SSteve Longerbeam 		return ret;
174819a81c14SSteve Longerbeam 	temp2 = temp1 & 0x03;
174919a81c14SSteve Longerbeam 	sclk_rdiv = sclk_rdiv_map[temp2];
175019a81c14SSteve Longerbeam 
175119a81c14SSteve Longerbeam 	if (!prediv || !sysdiv || !pll_rdiv || !bit_div2x)
175219a81c14SSteve Longerbeam 		return -EINVAL;
175319a81c14SSteve Longerbeam 
175419a81c14SSteve Longerbeam 	VCO = xvclk * multiplier / prediv;
175519a81c14SSteve Longerbeam 
175619a81c14SSteve Longerbeam 	sysclk = VCO / sysdiv / pll_rdiv * 2 / bit_div2x / sclk_rdiv;
175719a81c14SSteve Longerbeam 
175819a81c14SSteve Longerbeam 	return sysclk;
175919a81c14SSteve Longerbeam }
176019a81c14SSteve Longerbeam 
176119a81c14SSteve Longerbeam static int ov5640_set_night_mode(struct ov5640_dev *sensor)
176219a81c14SSteve Longerbeam {
176319a81c14SSteve Longerbeam 	 /* read HTS from register settings */
176419a81c14SSteve Longerbeam 	u8 mode;
176519a81c14SSteve Longerbeam 	int ret;
176619a81c14SSteve Longerbeam 
176719a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_CTRL00, &mode);
176819a81c14SSteve Longerbeam 	if (ret)
176919a81c14SSteve Longerbeam 		return ret;
177019a81c14SSteve Longerbeam 	mode &= 0xfb;
177119a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL00, mode);
177219a81c14SSteve Longerbeam }
177319a81c14SSteve Longerbeam 
177419a81c14SSteve Longerbeam static int ov5640_get_hts(struct ov5640_dev *sensor)
177519a81c14SSteve Longerbeam {
177619a81c14SSteve Longerbeam 	/* read HTS from register settings */
177719a81c14SSteve Longerbeam 	u16 hts;
177819a81c14SSteve Longerbeam 	int ret;
177919a81c14SSteve Longerbeam 
178019a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_HTS, &hts);
178119a81c14SSteve Longerbeam 	if (ret)
178219a81c14SSteve Longerbeam 		return ret;
178319a81c14SSteve Longerbeam 	return hts;
178419a81c14SSteve Longerbeam }
178519a81c14SSteve Longerbeam 
178619a81c14SSteve Longerbeam static int ov5640_get_vts(struct ov5640_dev *sensor)
178719a81c14SSteve Longerbeam {
178819a81c14SSteve Longerbeam 	u16 vts;
178919a81c14SSteve Longerbeam 	int ret;
179019a81c14SSteve Longerbeam 
179119a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_VTS, &vts);
179219a81c14SSteve Longerbeam 	if (ret)
179319a81c14SSteve Longerbeam 		return ret;
179419a81c14SSteve Longerbeam 	return vts;
179519a81c14SSteve Longerbeam }
179619a81c14SSteve Longerbeam 
179719a81c14SSteve Longerbeam static int ov5640_set_vts(struct ov5640_dev *sensor, int vts)
179819a81c14SSteve Longerbeam {
179919a81c14SSteve Longerbeam 	return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, vts);
180019a81c14SSteve Longerbeam }
180119a81c14SSteve Longerbeam 
180219a81c14SSteve Longerbeam static int ov5640_get_light_freq(struct ov5640_dev *sensor)
180319a81c14SSteve Longerbeam {
180419a81c14SSteve Longerbeam 	/* get banding filter value */
180519a81c14SSteve Longerbeam 	int ret, light_freq = 0;
180619a81c14SSteve Longerbeam 	u8 temp, temp1;
180719a81c14SSteve Longerbeam 
180819a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL01, &temp);
180919a81c14SSteve Longerbeam 	if (ret)
181019a81c14SSteve Longerbeam 		return ret;
181119a81c14SSteve Longerbeam 
181219a81c14SSteve Longerbeam 	if (temp & 0x80) {
181319a81c14SSteve Longerbeam 		/* manual */
181419a81c14SSteve Longerbeam 		ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL00,
181519a81c14SSteve Longerbeam 				      &temp1);
181619a81c14SSteve Longerbeam 		if (ret)
181719a81c14SSteve Longerbeam 			return ret;
181819a81c14SSteve Longerbeam 		if (temp1 & 0x04) {
181919a81c14SSteve Longerbeam 			/* 50Hz */
182019a81c14SSteve Longerbeam 			light_freq = 50;
182119a81c14SSteve Longerbeam 		} else {
182219a81c14SSteve Longerbeam 			/* 60Hz */
182319a81c14SSteve Longerbeam 			light_freq = 60;
182419a81c14SSteve Longerbeam 		}
182519a81c14SSteve Longerbeam 	} else {
182619a81c14SSteve Longerbeam 		/* auto */
182719a81c14SSteve Longerbeam 		ret = ov5640_read_reg(sensor, OV5640_REG_SIGMADELTA_CTRL0C,
182819a81c14SSteve Longerbeam 				      &temp1);
182919a81c14SSteve Longerbeam 		if (ret)
183019a81c14SSteve Longerbeam 			return ret;
183119a81c14SSteve Longerbeam 
183219a81c14SSteve Longerbeam 		if (temp1 & 0x01) {
183319a81c14SSteve Longerbeam 			/* 50Hz */
183419a81c14SSteve Longerbeam 			light_freq = 50;
183519a81c14SSteve Longerbeam 		} else {
183619a81c14SSteve Longerbeam 			/* 60Hz */
183719a81c14SSteve Longerbeam 		}
183819a81c14SSteve Longerbeam 	}
183919a81c14SSteve Longerbeam 
184019a81c14SSteve Longerbeam 	return light_freq;
184119a81c14SSteve Longerbeam }
184219a81c14SSteve Longerbeam 
184319a81c14SSteve Longerbeam static int ov5640_set_bandingfilter(struct ov5640_dev *sensor)
184419a81c14SSteve Longerbeam {
184519a81c14SSteve Longerbeam 	u32 band_step60, max_band60, band_step50, max_band50, prev_vts;
184619a81c14SSteve Longerbeam 	int ret;
184719a81c14SSteve Longerbeam 
184819a81c14SSteve Longerbeam 	/* read preview PCLK */
184919a81c14SSteve Longerbeam 	ret = ov5640_get_sysclk(sensor);
185019a81c14SSteve Longerbeam 	if (ret < 0)
185119a81c14SSteve Longerbeam 		return ret;
185219a81c14SSteve Longerbeam 	if (ret == 0)
185319a81c14SSteve Longerbeam 		return -EINVAL;
185419a81c14SSteve Longerbeam 	sensor->prev_sysclk = ret;
185519a81c14SSteve Longerbeam 	/* read preview HTS */
185619a81c14SSteve Longerbeam 	ret = ov5640_get_hts(sensor);
185719a81c14SSteve Longerbeam 	if (ret < 0)
185819a81c14SSteve Longerbeam 		return ret;
185919a81c14SSteve Longerbeam 	if (ret == 0)
186019a81c14SSteve Longerbeam 		return -EINVAL;
186119a81c14SSteve Longerbeam 	sensor->prev_hts = ret;
186219a81c14SSteve Longerbeam 
186319a81c14SSteve Longerbeam 	/* read preview VTS */
186419a81c14SSteve Longerbeam 	ret = ov5640_get_vts(sensor);
186519a81c14SSteve Longerbeam 	if (ret < 0)
186619a81c14SSteve Longerbeam 		return ret;
186719a81c14SSteve Longerbeam 	prev_vts = ret;
186819a81c14SSteve Longerbeam 
186919a81c14SSteve Longerbeam 	/* calculate banding filter */
187019a81c14SSteve Longerbeam 	/* 60Hz */
187119a81c14SSteve Longerbeam 	band_step60 = sensor->prev_sysclk * 100 / sensor->prev_hts * 100 / 120;
187219a81c14SSteve Longerbeam 	ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B60_STEP, band_step60);
187319a81c14SSteve Longerbeam 	if (ret)
187419a81c14SSteve Longerbeam 		return ret;
187519a81c14SSteve Longerbeam 	if (!band_step60)
187619a81c14SSteve Longerbeam 		return -EINVAL;
187719a81c14SSteve Longerbeam 	max_band60 = (int)((prev_vts - 4) / band_step60);
187819a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0D, max_band60);
187919a81c14SSteve Longerbeam 	if (ret)
188019a81c14SSteve Longerbeam 		return ret;
188119a81c14SSteve Longerbeam 
188219a81c14SSteve Longerbeam 	/* 50Hz */
188319a81c14SSteve Longerbeam 	band_step50 = sensor->prev_sysclk * 100 / sensor->prev_hts;
188419a81c14SSteve Longerbeam 	ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B50_STEP, band_step50);
188519a81c14SSteve Longerbeam 	if (ret)
188619a81c14SSteve Longerbeam 		return ret;
188719a81c14SSteve Longerbeam 	if (!band_step50)
188819a81c14SSteve Longerbeam 		return -EINVAL;
188919a81c14SSteve Longerbeam 	max_band50 = (int)((prev_vts - 4) / band_step50);
189019a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0E, max_band50);
189119a81c14SSteve Longerbeam }
189219a81c14SSteve Longerbeam 
189319a81c14SSteve Longerbeam static int ov5640_set_ae_target(struct ov5640_dev *sensor, int target)
189419a81c14SSteve Longerbeam {
189519a81c14SSteve Longerbeam 	/* stable in high */
189619a81c14SSteve Longerbeam 	u32 fast_high, fast_low;
189719a81c14SSteve Longerbeam 	int ret;
189819a81c14SSteve Longerbeam 
189919a81c14SSteve Longerbeam 	sensor->ae_low = target * 23 / 25;	/* 0.92 */
190019a81c14SSteve Longerbeam 	sensor->ae_high = target * 27 / 25;	/* 1.08 */
190119a81c14SSteve Longerbeam 
190219a81c14SSteve Longerbeam 	fast_high = sensor->ae_high << 1;
190319a81c14SSteve Longerbeam 	if (fast_high > 255)
190419a81c14SSteve Longerbeam 		fast_high = 255;
190519a81c14SSteve Longerbeam 
190619a81c14SSteve Longerbeam 	fast_low = sensor->ae_low >> 1;
190719a81c14SSteve Longerbeam 
190819a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0F, sensor->ae_high);
190919a81c14SSteve Longerbeam 	if (ret)
191019a81c14SSteve Longerbeam 		return ret;
191119a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL10, sensor->ae_low);
191219a81c14SSteve Longerbeam 	if (ret)
191319a81c14SSteve Longerbeam 		return ret;
191419a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1B, sensor->ae_high);
191519a81c14SSteve Longerbeam 	if (ret)
191619a81c14SSteve Longerbeam 		return ret;
191719a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1E, sensor->ae_low);
191819a81c14SSteve Longerbeam 	if (ret)
191919a81c14SSteve Longerbeam 		return ret;
192019a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL11, fast_high);
192119a81c14SSteve Longerbeam 	if (ret)
192219a81c14SSteve Longerbeam 		return ret;
192319a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1F, fast_low);
192419a81c14SSteve Longerbeam }
192519a81c14SSteve Longerbeam 
1926c2c3f42dSHugues Fruchet static int ov5640_get_binning(struct ov5640_dev *sensor)
192719a81c14SSteve Longerbeam {
192819a81c14SSteve Longerbeam 	u8 temp;
192919a81c14SSteve Longerbeam 	int ret;
193019a81c14SSteve Longerbeam 
193119a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_TIMING_TC_REG21, &temp);
193219a81c14SSteve Longerbeam 	if (ret)
193319a81c14SSteve Longerbeam 		return ret;
1934c2c3f42dSHugues Fruchet 
1935c2c3f42dSHugues Fruchet 	return temp & BIT(0);
193619a81c14SSteve Longerbeam }
193719a81c14SSteve Longerbeam 
1938ce85705aSHugues Fruchet static int ov5640_set_binning(struct ov5640_dev *sensor, bool enable)
1939ce85705aSHugues Fruchet {
1940ce85705aSHugues Fruchet 	int ret;
1941ce85705aSHugues Fruchet 
1942ce85705aSHugues Fruchet 	/*
1943ce85705aSHugues Fruchet 	 * TIMING TC REG21:
1944ce85705aSHugues Fruchet 	 * - [0]:	Horizontal binning enable
1945ce85705aSHugues Fruchet 	 */
1946ce85705aSHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
1947ce85705aSHugues Fruchet 			     BIT(0), enable ? BIT(0) : 0);
1948ce85705aSHugues Fruchet 	if (ret)
1949ce85705aSHugues Fruchet 		return ret;
1950ce85705aSHugues Fruchet 	/*
1951ce85705aSHugues Fruchet 	 * TIMING TC REG20:
1952ce85705aSHugues Fruchet 	 * - [0]:	Undocumented, but hardcoded init sequences
1953ce85705aSHugues Fruchet 	 *		are always setting REG21/REG20 bit 0 to same value...
1954ce85705aSHugues Fruchet 	 */
1955ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20,
1956ce85705aSHugues Fruchet 			      BIT(0), enable ? BIT(0) : 0);
1957ce85705aSHugues Fruchet }
1958ce85705aSHugues Fruchet 
195919a81c14SSteve Longerbeam static int ov5640_set_virtual_channel(struct ov5640_dev *sensor)
196019a81c14SSteve Longerbeam {
19618670d70aSHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
196219a81c14SSteve Longerbeam 	u8 temp, channel = virtual_channel;
196319a81c14SSteve Longerbeam 	int ret;
196419a81c14SSteve Longerbeam 
19658670d70aSHugues Fruchet 	if (channel > 3) {
19668670d70aSHugues Fruchet 		dev_err(&client->dev,
19678670d70aSHugues Fruchet 			"%s: wrong virtual_channel parameter, expected (0..3), got %d\n",
19688670d70aSHugues Fruchet 			__func__, channel);
196919a81c14SSteve Longerbeam 		return -EINVAL;
19708670d70aSHugues Fruchet 	}
197119a81c14SSteve Longerbeam 
197219a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_DEBUG_MODE, &temp);
197319a81c14SSteve Longerbeam 	if (ret)
197419a81c14SSteve Longerbeam 		return ret;
197519a81c14SSteve Longerbeam 	temp &= ~(3 << 6);
197619a81c14SSteve Longerbeam 	temp |= (channel << 6);
197719a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_DEBUG_MODE, temp);
197819a81c14SSteve Longerbeam }
197919a81c14SSteve Longerbeam 
198019a81c14SSteve Longerbeam static const struct ov5640_mode_info *
198119a81c14SSteve Longerbeam ov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr,
198219a81c14SSteve Longerbeam 		 int width, int height, bool nearest)
198319a81c14SSteve Longerbeam {
19843c4a7372SHugues Fruchet 	const struct ov5640_mode_info *mode;
198519a81c14SSteve Longerbeam 
1986086c25f8SMaxime Ripard 	mode = v4l2_find_nearest_size(ov5640_mode_data,
1987086c25f8SMaxime Ripard 				      ARRAY_SIZE(ov5640_mode_data),
19885113d5b3SJacopo Mondi 				      width, height, width, height);
198919a81c14SSteve Longerbeam 
19903c4a7372SHugues Fruchet 	if (!mode ||
19913145efcdSJacopo Mondi 	    (!nearest &&
19925113d5b3SJacopo Mondi 	     (mode->width != width || mode->height != height)))
19933c4a7372SHugues Fruchet 		return NULL;
199419a81c14SSteve Longerbeam 
19955554c80eSAdam Ford 	/* Check to see if the current mode exceeds the max frame rate */
19965554c80eSAdam Ford 	if (ov5640_framerates[fr] > ov5640_framerates[mode->max_fps])
1997981e4454SBenoit Parrot 		return NULL;
1998981e4454SBenoit Parrot 
199919a81c14SSteve Longerbeam 	return mode;
200019a81c14SSteve Longerbeam }
200119a81c14SSteve Longerbeam 
200219a81c14SSteve Longerbeam /*
200319a81c14SSteve Longerbeam  * sensor changes between scaling and subsampling, go through
200419a81c14SSteve Longerbeam  * exposure calculation
200519a81c14SSteve Longerbeam  */
200641d8d7f5SHugues Fruchet static int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor,
200741d8d7f5SHugues Fruchet 					 const struct ov5640_mode_info *mode)
200819a81c14SSteve Longerbeam {
200919a81c14SSteve Longerbeam 	u32 prev_shutter, prev_gain16;
201019a81c14SSteve Longerbeam 	u32 cap_shutter, cap_gain16;
201119a81c14SSteve Longerbeam 	u32 cap_sysclk, cap_hts, cap_vts;
201219a81c14SSteve Longerbeam 	u32 light_freq, cap_bandfilt, cap_maxband;
201319a81c14SSteve Longerbeam 	u32 cap_gain16_shutter;
201419a81c14SSteve Longerbeam 	u8 average;
201519a81c14SSteve Longerbeam 	int ret;
201619a81c14SSteve Longerbeam 
201741d8d7f5SHugues Fruchet 	if (!mode->reg_data)
201819a81c14SSteve Longerbeam 		return -EINVAL;
201919a81c14SSteve Longerbeam 
202019a81c14SSteve Longerbeam 	/* read preview shutter */
202119a81c14SSteve Longerbeam 	ret = ov5640_get_exposure(sensor);
202219a81c14SSteve Longerbeam 	if (ret < 0)
202319a81c14SSteve Longerbeam 		return ret;
202419a81c14SSteve Longerbeam 	prev_shutter = ret;
2025c2c3f42dSHugues Fruchet 	ret = ov5640_get_binning(sensor);
202619a81c14SSteve Longerbeam 	if (ret < 0)
202719a81c14SSteve Longerbeam 		return ret;
202819a81c14SSteve Longerbeam 	if (ret && mode->id != OV5640_MODE_720P_1280_720 &&
202919a81c14SSteve Longerbeam 	    mode->id != OV5640_MODE_1080P_1920_1080)
203019a81c14SSteve Longerbeam 		prev_shutter *= 2;
203119a81c14SSteve Longerbeam 
203219a81c14SSteve Longerbeam 	/* read preview gain */
203319a81c14SSteve Longerbeam 	ret = ov5640_get_gain(sensor);
203419a81c14SSteve Longerbeam 	if (ret < 0)
203519a81c14SSteve Longerbeam 		return ret;
203619a81c14SSteve Longerbeam 	prev_gain16 = ret;
203719a81c14SSteve Longerbeam 
203819a81c14SSteve Longerbeam 	/* get average */
203919a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AVG_READOUT, &average);
204019a81c14SSteve Longerbeam 	if (ret)
204119a81c14SSteve Longerbeam 		return ret;
204219a81c14SSteve Longerbeam 
204319a81c14SSteve Longerbeam 	/* turn off night mode for capture */
204419a81c14SSteve Longerbeam 	ret = ov5640_set_night_mode(sensor);
204519a81c14SSteve Longerbeam 	if (ret < 0)
204619a81c14SSteve Longerbeam 		return ret;
204719a81c14SSteve Longerbeam 
204819a81c14SSteve Longerbeam 	/* Write capture setting */
2049*e4359019SJacopo Mondi 	ov5640_load_regs(sensor, mode->reg_data, mode->reg_data_size);
2050*e4359019SJacopo Mondi 	ret = ov5640_set_timings(sensor, mode);
205119a81c14SSteve Longerbeam 	if (ret < 0)
205219a81c14SSteve Longerbeam 		return ret;
205319a81c14SSteve Longerbeam 
205419a81c14SSteve Longerbeam 	/* read capture VTS */
205519a81c14SSteve Longerbeam 	ret = ov5640_get_vts(sensor);
205619a81c14SSteve Longerbeam 	if (ret < 0)
205719a81c14SSteve Longerbeam 		return ret;
205819a81c14SSteve Longerbeam 	cap_vts = ret;
205919a81c14SSteve Longerbeam 	ret = ov5640_get_hts(sensor);
206019a81c14SSteve Longerbeam 	if (ret < 0)
206119a81c14SSteve Longerbeam 		return ret;
206219a81c14SSteve Longerbeam 	if (ret == 0)
206319a81c14SSteve Longerbeam 		return -EINVAL;
206419a81c14SSteve Longerbeam 	cap_hts = ret;
206519a81c14SSteve Longerbeam 
206619a81c14SSteve Longerbeam 	ret = ov5640_get_sysclk(sensor);
206719a81c14SSteve Longerbeam 	if (ret < 0)
206819a81c14SSteve Longerbeam 		return ret;
206919a81c14SSteve Longerbeam 	if (ret == 0)
207019a81c14SSteve Longerbeam 		return -EINVAL;
207119a81c14SSteve Longerbeam 	cap_sysclk = ret;
207219a81c14SSteve Longerbeam 
207319a81c14SSteve Longerbeam 	/* calculate capture banding filter */
207419a81c14SSteve Longerbeam 	ret = ov5640_get_light_freq(sensor);
207519a81c14SSteve Longerbeam 	if (ret < 0)
207619a81c14SSteve Longerbeam 		return ret;
207719a81c14SSteve Longerbeam 	light_freq = ret;
207819a81c14SSteve Longerbeam 
207919a81c14SSteve Longerbeam 	if (light_freq == 60) {
208019a81c14SSteve Longerbeam 		/* 60Hz */
208119a81c14SSteve Longerbeam 		cap_bandfilt = cap_sysclk * 100 / cap_hts * 100 / 120;
208219a81c14SSteve Longerbeam 	} else {
208319a81c14SSteve Longerbeam 		/* 50Hz */
208419a81c14SSteve Longerbeam 		cap_bandfilt = cap_sysclk * 100 / cap_hts;
208519a81c14SSteve Longerbeam 	}
208619a81c14SSteve Longerbeam 
208719a81c14SSteve Longerbeam 	if (!sensor->prev_sysclk) {
208819a81c14SSteve Longerbeam 		ret = ov5640_get_sysclk(sensor);
208919a81c14SSteve Longerbeam 		if (ret < 0)
209019a81c14SSteve Longerbeam 			return ret;
209119a81c14SSteve Longerbeam 		if (ret == 0)
209219a81c14SSteve Longerbeam 			return -EINVAL;
209319a81c14SSteve Longerbeam 		sensor->prev_sysclk = ret;
209419a81c14SSteve Longerbeam 	}
209519a81c14SSteve Longerbeam 
209619a81c14SSteve Longerbeam 	if (!cap_bandfilt)
209719a81c14SSteve Longerbeam 		return -EINVAL;
209819a81c14SSteve Longerbeam 
209919a81c14SSteve Longerbeam 	cap_maxband = (int)((cap_vts - 4) / cap_bandfilt);
210019a81c14SSteve Longerbeam 
210119a81c14SSteve Longerbeam 	/* calculate capture shutter/gain16 */
210219a81c14SSteve Longerbeam 	if (average > sensor->ae_low && average < sensor->ae_high) {
210319a81c14SSteve Longerbeam 		/* in stable range */
210419a81c14SSteve Longerbeam 		cap_gain16_shutter =
210519a81c14SSteve Longerbeam 			prev_gain16 * prev_shutter *
210619a81c14SSteve Longerbeam 			cap_sysclk / sensor->prev_sysclk *
210719a81c14SSteve Longerbeam 			sensor->prev_hts / cap_hts *
210819a81c14SSteve Longerbeam 			sensor->ae_target / average;
210919a81c14SSteve Longerbeam 	} else {
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 	}
211519a81c14SSteve Longerbeam 
211619a81c14SSteve Longerbeam 	/* gain to shutter */
211719a81c14SSteve Longerbeam 	if (cap_gain16_shutter < (cap_bandfilt * 16)) {
211819a81c14SSteve Longerbeam 		/* shutter < 1/100 */
211919a81c14SSteve Longerbeam 		cap_shutter = cap_gain16_shutter / 16;
212019a81c14SSteve Longerbeam 		if (cap_shutter < 1)
212119a81c14SSteve Longerbeam 			cap_shutter = 1;
212219a81c14SSteve Longerbeam 
212319a81c14SSteve Longerbeam 		cap_gain16 = cap_gain16_shutter / cap_shutter;
212419a81c14SSteve Longerbeam 		if (cap_gain16 < 16)
212519a81c14SSteve Longerbeam 			cap_gain16 = 16;
212619a81c14SSteve Longerbeam 	} else {
212719a81c14SSteve Longerbeam 		if (cap_gain16_shutter > (cap_bandfilt * cap_maxband * 16)) {
212819a81c14SSteve Longerbeam 			/* exposure reach max */
212919a81c14SSteve Longerbeam 			cap_shutter = cap_bandfilt * cap_maxband;
213019a81c14SSteve Longerbeam 			if (!cap_shutter)
213119a81c14SSteve Longerbeam 				return -EINVAL;
213219a81c14SSteve Longerbeam 
213319a81c14SSteve Longerbeam 			cap_gain16 = cap_gain16_shutter / cap_shutter;
213419a81c14SSteve Longerbeam 		} else {
213519a81c14SSteve Longerbeam 			/* 1/100 < (cap_shutter = n/100) =< max */
213619a81c14SSteve Longerbeam 			cap_shutter =
213719a81c14SSteve Longerbeam 				((int)(cap_gain16_shutter / 16 / cap_bandfilt))
213819a81c14SSteve Longerbeam 				* cap_bandfilt;
213919a81c14SSteve Longerbeam 			if (!cap_shutter)
214019a81c14SSteve Longerbeam 				return -EINVAL;
214119a81c14SSteve Longerbeam 
214219a81c14SSteve Longerbeam 			cap_gain16 = cap_gain16_shutter / cap_shutter;
214319a81c14SSteve Longerbeam 		}
214419a81c14SSteve Longerbeam 	}
214519a81c14SSteve Longerbeam 
214619a81c14SSteve Longerbeam 	/* set capture gain */
21473cca8ef5SHugues Fruchet 	ret = ov5640_set_gain(sensor, cap_gain16);
214819a81c14SSteve Longerbeam 	if (ret)
214919a81c14SSteve Longerbeam 		return ret;
215019a81c14SSteve Longerbeam 
215119a81c14SSteve Longerbeam 	/* write capture shutter */
215219a81c14SSteve Longerbeam 	if (cap_shutter > (cap_vts - 4)) {
215319a81c14SSteve Longerbeam 		cap_vts = cap_shutter + 4;
215419a81c14SSteve Longerbeam 		ret = ov5640_set_vts(sensor, cap_vts);
215519a81c14SSteve Longerbeam 		if (ret < 0)
215619a81c14SSteve Longerbeam 			return ret;
215719a81c14SSteve Longerbeam 	}
215819a81c14SSteve Longerbeam 
215919a81c14SSteve Longerbeam 	/* set exposure */
21603cca8ef5SHugues Fruchet 	return ov5640_set_exposure(sensor, cap_shutter);
216119a81c14SSteve Longerbeam }
216219a81c14SSteve Longerbeam 
216319a81c14SSteve Longerbeam /*
216419a81c14SSteve Longerbeam  * if sensor changes inside scaling or subsampling
216519a81c14SSteve Longerbeam  * change mode directly
216619a81c14SSteve Longerbeam  */
216719a81c14SSteve Longerbeam static int ov5640_set_mode_direct(struct ov5640_dev *sensor,
21683cca8ef5SHugues Fruchet 				  const struct ov5640_mode_info *mode)
216919a81c14SSteve Longerbeam {
217041d8d7f5SHugues Fruchet 	if (!mode->reg_data)
217119a81c14SSteve Longerbeam 		return -EINVAL;
217219a81c14SSteve Longerbeam 
217319a81c14SSteve Longerbeam 	/* Write capture setting */
2174*e4359019SJacopo Mondi 	ov5640_load_regs(sensor, mode->reg_data, mode->reg_data_size);
2175*e4359019SJacopo Mondi 	return ov5640_set_timings(sensor, mode);
217619a81c14SSteve Longerbeam }
217719a81c14SSteve Longerbeam 
2178985cdcb0SHugues Fruchet static int ov5640_set_mode(struct ov5640_dev *sensor)
217919a81c14SSteve Longerbeam {
218019a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode = sensor->current_mode;
2181985cdcb0SHugues Fruchet 	const struct ov5640_mode_info *orig_mode = sensor->last_mode;
218219a81c14SSteve Longerbeam 	enum ov5640_downsize_mode dn_mode, orig_dn_mode;
21833cca8ef5SHugues Fruchet 	bool auto_gain = sensor->ctrls.auto_gain->val == 1;
2184dc29a1c1SHugues Fruchet 	bool auto_exp =  sensor->ctrls.auto_exp->val == V4L2_EXPOSURE_AUTO;
218519a81c14SSteve Longerbeam 	int ret;
218619a81c14SSteve Longerbeam 
218719a81c14SSteve Longerbeam 	dn_mode = mode->dn_mode;
218819a81c14SSteve Longerbeam 	orig_dn_mode = orig_mode->dn_mode;
218919a81c14SSteve Longerbeam 
219019a81c14SSteve Longerbeam 	/* auto gain and exposure must be turned off when changing modes */
21913cca8ef5SHugues Fruchet 	if (auto_gain) {
21923cca8ef5SHugues Fruchet 		ret = ov5640_set_autogain(sensor, false);
219319a81c14SSteve Longerbeam 		if (ret)
219419a81c14SSteve Longerbeam 			return ret;
21953cca8ef5SHugues Fruchet 	}
2196bf4a4b51SMaxime Ripard 
21973cca8ef5SHugues Fruchet 	if (auto_exp) {
2198dc29a1c1SHugues Fruchet 		ret = ov5640_set_autoexposure(sensor, false);
219919a81c14SSteve Longerbeam 		if (ret)
22003cca8ef5SHugues Fruchet 			goto restore_auto_gain;
22013cca8ef5SHugues Fruchet 	}
220219a81c14SSteve Longerbeam 
22036c957ed7SJacopo Mondi 	if (ov5640_is_csi2(sensor))
22046c957ed7SJacopo Mondi 		ret = ov5640_set_mipi_pclk(sensor);
22056c957ed7SJacopo Mondi 	else
22066c957ed7SJacopo Mondi 		ret = ov5640_set_dvp_pclk(sensor);
2207aa288248SMaxime Ripard 	if (ret < 0)
2208aa288248SMaxime Ripard 		return 0;
2209aa288248SMaxime Ripard 
221019a81c14SSteve Longerbeam 	if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) ||
221119a81c14SSteve Longerbeam 	    (dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) {
221219a81c14SSteve Longerbeam 		/*
221319a81c14SSteve Longerbeam 		 * change between subsampling and scaling
22143cca8ef5SHugues Fruchet 		 * go through exposure calculation
221519a81c14SSteve Longerbeam 		 */
221619a81c14SSteve Longerbeam 		ret = ov5640_set_mode_exposure_calc(sensor, mode);
221719a81c14SSteve Longerbeam 	} else {
221819a81c14SSteve Longerbeam 		/*
221919a81c14SSteve Longerbeam 		 * change inside subsampling or scaling
222019a81c14SSteve Longerbeam 		 * download firmware directly
222119a81c14SSteve Longerbeam 		 */
22223cca8ef5SHugues Fruchet 		ret = ov5640_set_mode_direct(sensor, mode);
222319a81c14SSteve Longerbeam 	}
222419a81c14SSteve Longerbeam 	if (ret < 0)
22253cca8ef5SHugues Fruchet 		goto restore_auto_exp_gain;
22263cca8ef5SHugues Fruchet 
22273cca8ef5SHugues Fruchet 	/* restore auto gain and exposure */
22283cca8ef5SHugues Fruchet 	if (auto_gain)
22293cca8ef5SHugues Fruchet 		ov5640_set_autogain(sensor, true);
22303cca8ef5SHugues Fruchet 	if (auto_exp)
22313cca8ef5SHugues Fruchet 		ov5640_set_autoexposure(sensor, true);
223219a81c14SSteve Longerbeam 
2233ce85705aSHugues Fruchet 	ret = ov5640_set_binning(sensor, dn_mode != SCALING);
2234ce85705aSHugues Fruchet 	if (ret < 0)
2235ce85705aSHugues Fruchet 		return ret;
223619a81c14SSteve Longerbeam 	ret = ov5640_set_ae_target(sensor, sensor->ae_target);
223719a81c14SSteve Longerbeam 	if (ret < 0)
223819a81c14SSteve Longerbeam 		return ret;
223919a81c14SSteve Longerbeam 	ret = ov5640_get_light_freq(sensor);
224019a81c14SSteve Longerbeam 	if (ret < 0)
224119a81c14SSteve Longerbeam 		return ret;
224219a81c14SSteve Longerbeam 	ret = ov5640_set_bandingfilter(sensor);
224319a81c14SSteve Longerbeam 	if (ret < 0)
224419a81c14SSteve Longerbeam 		return ret;
224519a81c14SSteve Longerbeam 	ret = ov5640_set_virtual_channel(sensor);
224619a81c14SSteve Longerbeam 	if (ret < 0)
224719a81c14SSteve Longerbeam 		return ret;
224819a81c14SSteve Longerbeam 
224919a81c14SSteve Longerbeam 	sensor->pending_mode_change = false;
2250985cdcb0SHugues Fruchet 	sensor->last_mode = mode;
225119a81c14SSteve Longerbeam 
225219a81c14SSteve Longerbeam 	return 0;
22533cca8ef5SHugues Fruchet 
22543cca8ef5SHugues Fruchet restore_auto_exp_gain:
22553cca8ef5SHugues Fruchet 	if (auto_exp)
22563cca8ef5SHugues Fruchet 		ov5640_set_autoexposure(sensor, true);
22573cca8ef5SHugues Fruchet restore_auto_gain:
22583cca8ef5SHugues Fruchet 	if (auto_gain)
22593cca8ef5SHugues Fruchet 		ov5640_set_autogain(sensor, true);
22603cca8ef5SHugues Fruchet 
22613cca8ef5SHugues Fruchet 	return ret;
226219a81c14SSteve Longerbeam }
226319a81c14SSteve Longerbeam 
226419ad26f9SAkinobu Mita static int ov5640_set_framefmt(struct ov5640_dev *sensor,
226519ad26f9SAkinobu Mita 			       struct v4l2_mbus_framefmt *format);
226619ad26f9SAkinobu Mita 
226719a81c14SSteve Longerbeam /* restore the last set video mode after chip power-on */
226819a81c14SSteve Longerbeam static int ov5640_restore_mode(struct ov5640_dev *sensor)
226919a81c14SSteve Longerbeam {
227019a81c14SSteve Longerbeam 	int ret;
227119a81c14SSteve Longerbeam 
227219a81c14SSteve Longerbeam 	/* first load the initial register values */
2273*e4359019SJacopo Mondi 	ov5640_load_regs(sensor, ov5640_init_setting,
2274*e4359019SJacopo Mondi 			 ARRAY_SIZE(ov5640_init_setting));
227519a81c14SSteve Longerbeam 
22768f57c2f8SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
22777851fe7aSMaxime Ripard 			     (ilog2(OV5640_SCLK2X_ROOT_DIV) << 2) |
22787851fe7aSMaxime Ripard 			     ilog2(OV5640_SCLK_ROOT_DIV));
22798f57c2f8SMaxime Ripard 	if (ret)
22808f57c2f8SMaxime Ripard 		return ret;
22818f57c2f8SMaxime Ripard 
228219a81c14SSteve Longerbeam 	/* now restore the last capture mode */
2283985cdcb0SHugues Fruchet 	ret = ov5640_set_mode(sensor);
228419ad26f9SAkinobu Mita 	if (ret < 0)
228519ad26f9SAkinobu Mita 		return ret;
228619ad26f9SAkinobu Mita 
228719ad26f9SAkinobu Mita 	return ov5640_set_framefmt(sensor, &sensor->fmt);
228819a81c14SSteve Longerbeam }
228919a81c14SSteve Longerbeam 
229019a81c14SSteve Longerbeam static void ov5640_power(struct ov5640_dev *sensor, bool enable)
229119a81c14SSteve Longerbeam {
22921fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->pwdn_gpio, enable ? 0 : 1);
229319a81c14SSteve Longerbeam }
229419a81c14SSteve Longerbeam 
229519a81c14SSteve Longerbeam static void ov5640_reset(struct ov5640_dev *sensor)
229619a81c14SSteve Longerbeam {
229719a81c14SSteve Longerbeam 	if (!sensor->reset_gpio)
229819a81c14SSteve Longerbeam 		return;
229919a81c14SSteve Longerbeam 
23001fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 0);
230119a81c14SSteve Longerbeam 
230219a81c14SSteve Longerbeam 	/* camera power cycle */
230319a81c14SSteve Longerbeam 	ov5640_power(sensor, false);
230419a81c14SSteve Longerbeam 	usleep_range(5000, 10000);
230519a81c14SSteve Longerbeam 	ov5640_power(sensor, true);
230619a81c14SSteve Longerbeam 	usleep_range(5000, 10000);
230719a81c14SSteve Longerbeam 
23081fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 1);
230919a81c14SSteve Longerbeam 	usleep_range(1000, 2000);
231019a81c14SSteve Longerbeam 
23111fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 0);
23121d4c41f3SLoic Poulain 	usleep_range(20000, 25000);
231319a81c14SSteve Longerbeam }
231419a81c14SSteve Longerbeam 
23150f7acb52SHugues Fruchet static int ov5640_set_power_on(struct ov5640_dev *sensor)
231619a81c14SSteve Longerbeam {
23170f7acb52SHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
23180f7acb52SHugues Fruchet 	int ret;
231919a81c14SSteve Longerbeam 
23200f7acb52SHugues Fruchet 	ret = clk_prepare_enable(sensor->xclk);
23210f7acb52SHugues Fruchet 	if (ret) {
23220f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to enable clock\n",
23230f7acb52SHugues Fruchet 			__func__);
23240f7acb52SHugues Fruchet 		return ret;
23250f7acb52SHugues Fruchet 	}
232619a81c14SSteve Longerbeam 
232719a81c14SSteve Longerbeam 	ret = regulator_bulk_enable(OV5640_NUM_SUPPLIES,
232819a81c14SSteve Longerbeam 				    sensor->supplies);
23290f7acb52SHugues Fruchet 	if (ret) {
23300f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to enable regulators\n",
23310f7acb52SHugues Fruchet 			__func__);
233219a81c14SSteve Longerbeam 		goto xclk_off;
23330f7acb52SHugues Fruchet 	}
233419a81c14SSteve Longerbeam 
233519a81c14SSteve Longerbeam 	ov5640_reset(sensor);
233619a81c14SSteve Longerbeam 	ov5640_power(sensor, true);
233719a81c14SSteve Longerbeam 
233819a81c14SSteve Longerbeam 	ret = ov5640_init_slave_id(sensor);
233919a81c14SSteve Longerbeam 	if (ret)
234019a81c14SSteve Longerbeam 		goto power_off;
234119a81c14SSteve Longerbeam 
23420f7acb52SHugues Fruchet 	return 0;
23430f7acb52SHugues Fruchet 
23440f7acb52SHugues Fruchet power_off:
23450f7acb52SHugues Fruchet 	ov5640_power(sensor, false);
23460f7acb52SHugues Fruchet 	regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies);
23470f7acb52SHugues Fruchet xclk_off:
23480f7acb52SHugues Fruchet 	clk_disable_unprepare(sensor->xclk);
23490f7acb52SHugues Fruchet 	return ret;
23500f7acb52SHugues Fruchet }
23510f7acb52SHugues Fruchet 
23520f7acb52SHugues Fruchet static void ov5640_set_power_off(struct ov5640_dev *sensor)
23530f7acb52SHugues Fruchet {
23540f7acb52SHugues Fruchet 	ov5640_power(sensor, false);
23550f7acb52SHugues Fruchet 	regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies);
23560f7acb52SHugues Fruchet 	clk_disable_unprepare(sensor->xclk);
23570f7acb52SHugues Fruchet }
23580f7acb52SHugues Fruchet 
2359b1751ae6SLad Prabhakar static int ov5640_set_power_mipi(struct ov5640_dev *sensor, bool on)
2360b1751ae6SLad Prabhakar {
2361b1751ae6SLad Prabhakar 	int ret;
2362b1751ae6SLad Prabhakar 
2363b1751ae6SLad Prabhakar 	if (!on) {
2364b1751ae6SLad Prabhakar 		/* Reset MIPI bus settings to their default values. */
2365b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
2366b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x04);
2367b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x00);
2368b1751ae6SLad Prabhakar 		return 0;
2369b1751ae6SLad Prabhakar 	}
2370b1751ae6SLad Prabhakar 
2371b1751ae6SLad Prabhakar 	/*
2372b1751ae6SLad Prabhakar 	 * Power up MIPI HS Tx and LS Rx; 2 data lanes mode
2373b1751ae6SLad Prabhakar 	 *
2374b1751ae6SLad Prabhakar 	 * 0x300e = 0x40
2375b1751ae6SLad Prabhakar 	 * [7:5] = 010	: 2 data lanes mode (see FIXME note in
2376b1751ae6SLad Prabhakar 	 *		  "ov5640_set_stream_mipi()")
2377b1751ae6SLad Prabhakar 	 * [4] = 0	: Power up MIPI HS Tx
2378b1751ae6SLad Prabhakar 	 * [3] = 0	: Power up MIPI LS Rx
2379b1751ae6SLad Prabhakar 	 * [2] = 0	: MIPI interface disabled
2380b1751ae6SLad Prabhakar 	 */
2381b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x40);
2382b1751ae6SLad Prabhakar 	if (ret)
2383b1751ae6SLad Prabhakar 		return ret;
2384b1751ae6SLad Prabhakar 
2385b1751ae6SLad Prabhakar 	/*
2386b1751ae6SLad Prabhakar 	 * Gate clock and set LP11 in 'no packets mode' (idle)
2387b1751ae6SLad Prabhakar 	 *
2388b1751ae6SLad Prabhakar 	 * 0x4800 = 0x24
2389b1751ae6SLad Prabhakar 	 * [5] = 1	: Gate clock when 'no packets'
2390b1751ae6SLad Prabhakar 	 * [2] = 1	: MIPI bus in LP11 when 'no packets'
2391b1751ae6SLad Prabhakar 	 */
2392b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x24);
2393b1751ae6SLad Prabhakar 	if (ret)
2394b1751ae6SLad Prabhakar 		return ret;
2395b1751ae6SLad Prabhakar 
2396b1751ae6SLad Prabhakar 	/*
2397b1751ae6SLad Prabhakar 	 * Set data lanes and clock in LP11 when 'sleeping'
2398b1751ae6SLad Prabhakar 	 *
2399b1751ae6SLad Prabhakar 	 * 0x3019 = 0x70
2400b1751ae6SLad Prabhakar 	 * [6] = 1	: MIPI data lane 2 in LP11 when 'sleeping'
2401b1751ae6SLad Prabhakar 	 * [5] = 1	: MIPI data lane 1 in LP11 when 'sleeping'
2402b1751ae6SLad Prabhakar 	 * [4] = 1	: MIPI clock lane in LP11 when 'sleeping'
2403b1751ae6SLad Prabhakar 	 */
2404b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x70);
2405b1751ae6SLad Prabhakar 	if (ret)
2406b1751ae6SLad Prabhakar 		return ret;
2407b1751ae6SLad Prabhakar 
2408b1751ae6SLad Prabhakar 	/* Give lanes some time to coax into LP11 state. */
2409b1751ae6SLad Prabhakar 	usleep_range(500, 1000);
2410b1751ae6SLad Prabhakar 
2411b1751ae6SLad Prabhakar 	return 0;
2412b1751ae6SLad Prabhakar }
2413b1751ae6SLad Prabhakar 
2414576f5d4bSLad Prabhakar static int ov5640_set_power_dvp(struct ov5640_dev *sensor, bool on)
2415576f5d4bSLad Prabhakar {
2416311a6408SLad Prabhakar 	unsigned int flags = sensor->ep.bus.parallel.flags;
241768579b32SHugues Fruchet 	bool bt656 = sensor->ep.bus_type == V4L2_MBUS_BT656;
241868579b32SHugues Fruchet 	u8 polarities = 0;
2419576f5d4bSLad Prabhakar 	int ret;
2420576f5d4bSLad Prabhakar 
2421576f5d4bSLad Prabhakar 	if (!on) {
2422576f5d4bSLad Prabhakar 		/* Reset settings to their default values. */
242368579b32SHugues Fruchet 		ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00, 0x00);
2424311a6408SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
2425311a6408SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, 0x20);
2426576f5d4bSLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01, 0x00);
2427576f5d4bSLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0x00);
2428576f5d4bSLad Prabhakar 		return 0;
2429576f5d4bSLad Prabhakar 	}
2430576f5d4bSLad Prabhakar 
2431576f5d4bSLad Prabhakar 	/*
2432311a6408SLad Prabhakar 	 * Note about parallel port configuration.
2433311a6408SLad Prabhakar 	 *
2434311a6408SLad Prabhakar 	 * When configured in parallel mode, the OV5640 will
2435311a6408SLad Prabhakar 	 * output 10 bits data on DVP data lines [9:0].
2436311a6408SLad Prabhakar 	 * If only 8 bits data are wanted, the 8 bits data lines
2437311a6408SLad Prabhakar 	 * of the camera interface must be physically connected
2438311a6408SLad Prabhakar 	 * on the DVP data lines [9:2].
2439311a6408SLad Prabhakar 	 *
2440311a6408SLad Prabhakar 	 * Control lines polarity can be configured through
2441311a6408SLad Prabhakar 	 * devicetree endpoint control lines properties.
2442311a6408SLad Prabhakar 	 * If no endpoint control lines properties are set,
2443311a6408SLad Prabhakar 	 * polarity will be as below:
2444311a6408SLad Prabhakar 	 * - VSYNC:	active high
2445311a6408SLad Prabhakar 	 * - HREF:	active low
2446311a6408SLad Prabhakar 	 * - PCLK:	active low
244768579b32SHugues Fruchet 	 *
244868579b32SHugues Fruchet 	 * VSYNC & HREF are not configured if BT656 bus mode is selected
2449311a6408SLad Prabhakar 	 */
245068579b32SHugues Fruchet 
245168579b32SHugues Fruchet 	/*
245268579b32SHugues Fruchet 	 * BT656 embedded synchronization configuration
245368579b32SHugues Fruchet 	 *
245468579b32SHugues Fruchet 	 * CCIR656 CTRL00
245568579b32SHugues Fruchet 	 * - [7]:	SYNC code selection (0: auto generate sync code,
245668579b32SHugues Fruchet 	 *		1: sync code from regs 0x4732-0x4735)
245768579b32SHugues Fruchet 	 * - [6]:	f value in CCIR656 SYNC code when fixed f value
245868579b32SHugues Fruchet 	 * - [5]:	Fixed f value
245968579b32SHugues Fruchet 	 * - [4:3]:	Blank toggle data options (00: data=1'h040/1'h200,
246068579b32SHugues Fruchet 	 *		01: data from regs 0x4736-0x4738, 10: always keep 0)
246168579b32SHugues Fruchet 	 * - [1]:	Clip data disable
246268579b32SHugues Fruchet 	 * - [0]:	CCIR656 mode enable
246368579b32SHugues Fruchet 	 *
246468579b32SHugues Fruchet 	 * Default CCIR656 SAV/EAV mode with default codes
246568579b32SHugues Fruchet 	 * SAV=0xff000080 & EAV=0xff00009d is enabled here with settings:
246668579b32SHugues Fruchet 	 * - CCIR656 mode enable
246768579b32SHugues Fruchet 	 * - auto generation of sync codes
246868579b32SHugues Fruchet 	 * - blank toggle data 1'h040/1'h200
246968579b32SHugues Fruchet 	 * - clip reserved data (0x00 & 0xff changed to 0x01 & 0xfe)
247068579b32SHugues Fruchet 	 */
247168579b32SHugues Fruchet 	ret = ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00,
247268579b32SHugues Fruchet 			       bt656 ? 0x01 : 0x00);
247368579b32SHugues Fruchet 	if (ret)
247468579b32SHugues Fruchet 		return ret;
247568579b32SHugues Fruchet 
2476311a6408SLad Prabhakar 	/*
2477311a6408SLad Prabhakar 	 * configure parallel port control lines polarity
2478311a6408SLad Prabhakar 	 *
2479311a6408SLad Prabhakar 	 * POLARITY CTRL0
2480311a6408SLad Prabhakar 	 * - [5]:	PCLK polarity (0: active low, 1: active high)
2481311a6408SLad Prabhakar 	 * - [1]:	HREF polarity (0: active low, 1: active high)
2482311a6408SLad Prabhakar 	 * - [0]:	VSYNC polarity (mismatch here between
2483311a6408SLad Prabhakar 	 *		datasheet and hardware, 0 is active high
2484311a6408SLad Prabhakar 	 *		and 1 is active low...)
2485311a6408SLad Prabhakar 	 */
248668579b32SHugues Fruchet 	if (!bt656) {
2487311a6408SLad Prabhakar 		if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
248868579b32SHugues Fruchet 			polarities |= BIT(1);
2489311a6408SLad Prabhakar 		if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
249068579b32SHugues Fruchet 			polarities |= BIT(0);
249168579b32SHugues Fruchet 	}
249268579b32SHugues Fruchet 	if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
249368579b32SHugues Fruchet 		polarities |= BIT(5);
2494311a6408SLad Prabhakar 
249568579b32SHugues Fruchet 	ret = ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, polarities);
2496311a6408SLad Prabhakar 	if (ret)
2497311a6408SLad Prabhakar 		return ret;
2498311a6408SLad Prabhakar 
2499311a6408SLad Prabhakar 	/*
250068579b32SHugues Fruchet 	 * powerdown MIPI TX/RX PHY & enable DVP
2501311a6408SLad Prabhakar 	 *
2502311a6408SLad Prabhakar 	 * MIPI CONTROL 00
250368579b32SHugues Fruchet 	 * [4] = 1	: Power down MIPI HS Tx
250468579b32SHugues Fruchet 	 * [3] = 1	: Power down MIPI LS Rx
250568579b32SHugues Fruchet 	 * [2] = 0	: DVP enable (MIPI disable)
2506311a6408SLad Prabhakar 	 */
2507311a6408SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x18);
2508311a6408SLad Prabhakar 	if (ret)
2509311a6408SLad Prabhakar 		return ret;
2510311a6408SLad Prabhakar 
2511311a6408SLad Prabhakar 	/*
2512576f5d4bSLad Prabhakar 	 * enable VSYNC/HREF/PCLK DVP control lines
2513576f5d4bSLad Prabhakar 	 * & D[9:6] DVP data lines
2514576f5d4bSLad Prabhakar 	 *
2515576f5d4bSLad Prabhakar 	 * PAD OUTPUT ENABLE 01
2516576f5d4bSLad Prabhakar 	 * - 6:		VSYNC output enable
2517576f5d4bSLad Prabhakar 	 * - 5:		HREF output enable
2518576f5d4bSLad Prabhakar 	 * - 4:		PCLK output enable
2519576f5d4bSLad Prabhakar 	 * - [3:0]:	D[9:6] output enable
2520576f5d4bSLad Prabhakar 	 */
25214039b037SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01,
252268579b32SHugues Fruchet 			       bt656 ? 0x1f : 0x7f);
2523576f5d4bSLad Prabhakar 	if (ret)
2524576f5d4bSLad Prabhakar 		return ret;
2525576f5d4bSLad Prabhakar 
2526576f5d4bSLad Prabhakar 	/*
2527576f5d4bSLad Prabhakar 	 * enable D[5:0] DVP data lines
2528576f5d4bSLad Prabhakar 	 *
2529576f5d4bSLad Prabhakar 	 * PAD OUTPUT ENABLE 02
2530576f5d4bSLad Prabhakar 	 * - [7:2]:	D[5:0] output enable
2531576f5d4bSLad Prabhakar 	 */
2532576f5d4bSLad Prabhakar 	return ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0xfc);
2533576f5d4bSLad Prabhakar }
2534576f5d4bSLad Prabhakar 
25350f7acb52SHugues Fruchet static int ov5640_set_power(struct ov5640_dev *sensor, bool on)
25360f7acb52SHugues Fruchet {
25370f7acb52SHugues Fruchet 	int ret = 0;
25380f7acb52SHugues Fruchet 
25390f7acb52SHugues Fruchet 	if (on) {
25400f7acb52SHugues Fruchet 		ret = ov5640_set_power_on(sensor);
25410f7acb52SHugues Fruchet 		if (ret)
25420f7acb52SHugues Fruchet 			return ret;
25430f7acb52SHugues Fruchet 
254419a81c14SSteve Longerbeam 		ret = ov5640_restore_mode(sensor);
254519a81c14SSteve Longerbeam 		if (ret)
254619a81c14SSteve Longerbeam 			goto power_off;
2547b1751ae6SLad Prabhakar 	}
254819a81c14SSteve Longerbeam 
2549576f5d4bSLad Prabhakar 	if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY)
2550b1751ae6SLad Prabhakar 		ret = ov5640_set_power_mipi(sensor, on);
2551576f5d4bSLad Prabhakar 	else
2552576f5d4bSLad Prabhakar 		ret = ov5640_set_power_dvp(sensor, on);
2553b1751ae6SLad Prabhakar 	if (ret)
2554b1751ae6SLad Prabhakar 		goto power_off;
2555aa4bb8b8SJacopo Mondi 
2556b1751ae6SLad Prabhakar 	if (!on)
2557aa4bb8b8SJacopo Mondi 		ov5640_set_power_off(sensor);
255819a81c14SSteve Longerbeam 
255919a81c14SSteve Longerbeam 	return 0;
256019a81c14SSteve Longerbeam 
256119a81c14SSteve Longerbeam power_off:
25620f7acb52SHugues Fruchet 	ov5640_set_power_off(sensor);
256319a81c14SSteve Longerbeam 	return ret;
256419a81c14SSteve Longerbeam }
256519a81c14SSteve Longerbeam 
256619a81c14SSteve Longerbeam /* --------------- Subdev Operations --------------- */
256719a81c14SSteve Longerbeam 
256819a81c14SSteve Longerbeam static int ov5640_s_power(struct v4l2_subdev *sd, int on)
256919a81c14SSteve Longerbeam {
257019a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
257119a81c14SSteve Longerbeam 	int ret = 0;
257219a81c14SSteve Longerbeam 
257319a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
257419a81c14SSteve Longerbeam 
257519a81c14SSteve Longerbeam 	/*
257619a81c14SSteve Longerbeam 	 * If the power count is modified from 0 to != 0 or from != 0 to 0,
257719a81c14SSteve Longerbeam 	 * update the power state.
257819a81c14SSteve Longerbeam 	 */
257919a81c14SSteve Longerbeam 	if (sensor->power_count == !on) {
258019a81c14SSteve Longerbeam 		ret = ov5640_set_power(sensor, !!on);
258119a81c14SSteve Longerbeam 		if (ret)
258219a81c14SSteve Longerbeam 			goto out;
258319a81c14SSteve Longerbeam 	}
258419a81c14SSteve Longerbeam 
258519a81c14SSteve Longerbeam 	/* Update the power count. */
258619a81c14SSteve Longerbeam 	sensor->power_count += on ? 1 : -1;
258719a81c14SSteve Longerbeam 	WARN_ON(sensor->power_count < 0);
258819a81c14SSteve Longerbeam out:
258919a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
259019a81c14SSteve Longerbeam 
259119a81c14SSteve Longerbeam 	if (on && !ret && sensor->power_count == 1) {
259219a81c14SSteve Longerbeam 		/* restore controls */
259319a81c14SSteve Longerbeam 		ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
259419a81c14SSteve Longerbeam 	}
259519a81c14SSteve Longerbeam 
259619a81c14SSteve Longerbeam 	return ret;
259719a81c14SSteve Longerbeam }
259819a81c14SSteve Longerbeam 
259919a81c14SSteve Longerbeam static int ov5640_try_frame_interval(struct ov5640_dev *sensor,
260019a81c14SSteve Longerbeam 				     struct v4l2_fract *fi,
260119a81c14SSteve Longerbeam 				     u32 width, u32 height)
260219a81c14SSteve Longerbeam {
260319a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
26046530a5ebSJagan Teki 	enum ov5640_frame_rate rate = OV5640_15_FPS;
2605f6cc192fSMaxime Ripard 	int minfps, maxfps, best_fps, fps;
2606f6cc192fSMaxime Ripard 	int i;
260719a81c14SSteve Longerbeam 
260819a81c14SSteve Longerbeam 	minfps = ov5640_framerates[OV5640_15_FPS];
2609e823fb16SMaxime Ripard 	maxfps = ov5640_framerates[OV5640_60_FPS];
261019a81c14SSteve Longerbeam 
261119a81c14SSteve Longerbeam 	if (fi->numerator == 0) {
261219a81c14SSteve Longerbeam 		fi->denominator = maxfps;
261319a81c14SSteve Longerbeam 		fi->numerator = 1;
2614e823fb16SMaxime Ripard 		rate = OV5640_60_FPS;
2615e823fb16SMaxime Ripard 		goto find_mode;
261619a81c14SSteve Longerbeam 	}
261719a81c14SSteve Longerbeam 
2618f6cc192fSMaxime Ripard 	fps = clamp_val(DIV_ROUND_CLOSEST(fi->denominator, fi->numerator),
2619f6cc192fSMaxime Ripard 			minfps, maxfps);
2620f6cc192fSMaxime Ripard 
2621f6cc192fSMaxime Ripard 	best_fps = minfps;
2622f6cc192fSMaxime Ripard 	for (i = 0; i < ARRAY_SIZE(ov5640_framerates); i++) {
2623f6cc192fSMaxime Ripard 		int curr_fps = ov5640_framerates[i];
2624f6cc192fSMaxime Ripard 
2625f6cc192fSMaxime Ripard 		if (abs(curr_fps - fps) < abs(best_fps - fps)) {
2626f6cc192fSMaxime Ripard 			best_fps = curr_fps;
2627f6cc192fSMaxime Ripard 			rate = i;
2628f6cc192fSMaxime Ripard 		}
2629f6cc192fSMaxime Ripard 	}
263019a81c14SSteve Longerbeam 
263119a81c14SSteve Longerbeam 	fi->numerator = 1;
2632f6cc192fSMaxime Ripard 	fi->denominator = best_fps;
263319a81c14SSteve Longerbeam 
2634e823fb16SMaxime Ripard find_mode:
26355a3ad937SMaxime Ripard 	mode = ov5640_find_mode(sensor, rate, width, height, false);
26365a3ad937SMaxime Ripard 	return mode ? rate : -EINVAL;
263719a81c14SSteve Longerbeam }
263819a81c14SSteve Longerbeam 
263919a81c14SSteve Longerbeam static int ov5640_get_fmt(struct v4l2_subdev *sd,
26400d346d2aSTomi Valkeinen 			  struct v4l2_subdev_state *sd_state,
264119a81c14SSteve Longerbeam 			  struct v4l2_subdev_format *format)
264219a81c14SSteve Longerbeam {
264319a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
264419a81c14SSteve Longerbeam 	struct v4l2_mbus_framefmt *fmt;
264519a81c14SSteve Longerbeam 
264619a81c14SSteve Longerbeam 	if (format->pad != 0)
264719a81c14SSteve Longerbeam 		return -EINVAL;
264819a81c14SSteve Longerbeam 
264919a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
265019a81c14SSteve Longerbeam 
265119a81c14SSteve Longerbeam 	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
26520d346d2aSTomi Valkeinen 		fmt = v4l2_subdev_get_try_format(&sensor->sd, sd_state,
265319a81c14SSteve Longerbeam 						 format->pad);
265419a81c14SSteve Longerbeam 	else
265519a81c14SSteve Longerbeam 		fmt = &sensor->fmt;
265619a81c14SSteve Longerbeam 
265719a81c14SSteve Longerbeam 	format->format = *fmt;
265819a81c14SSteve Longerbeam 
265919a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
266019a81c14SSteve Longerbeam 
266119a81c14SSteve Longerbeam 	return 0;
266219a81c14SSteve Longerbeam }
266319a81c14SSteve Longerbeam 
266419a81c14SSteve Longerbeam static int ov5640_try_fmt_internal(struct v4l2_subdev *sd,
266519a81c14SSteve Longerbeam 				   struct v4l2_mbus_framefmt *fmt,
266619a81c14SSteve Longerbeam 				   enum ov5640_frame_rate fr,
266719a81c14SSteve Longerbeam 				   const struct ov5640_mode_info **new_mode)
266819a81c14SSteve Longerbeam {
266919a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
267019a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
2671e3ee691dSHugues Fruchet 	int i;
267219a81c14SSteve Longerbeam 
267319a81c14SSteve Longerbeam 	mode = ov5640_find_mode(sensor, fr, fmt->width, fmt->height, true);
267419a81c14SSteve Longerbeam 	if (!mode)
267519a81c14SSteve Longerbeam 		return -EINVAL;
26765113d5b3SJacopo Mondi 	fmt->width = mode->width;
26775113d5b3SJacopo Mondi 	fmt->height = mode->height;
267819a81c14SSteve Longerbeam 
267919a81c14SSteve Longerbeam 	if (new_mode)
268019a81c14SSteve Longerbeam 		*new_mode = mode;
2681e3ee691dSHugues Fruchet 
2682e3ee691dSHugues Fruchet 	for (i = 0; i < ARRAY_SIZE(ov5640_formats); i++)
2683e3ee691dSHugues Fruchet 		if (ov5640_formats[i].code == fmt->code)
2684e3ee691dSHugues Fruchet 			break;
2685e3ee691dSHugues Fruchet 	if (i >= ARRAY_SIZE(ov5640_formats))
2686e6441fdeSHugues Fruchet 		i = 0;
2687e6441fdeSHugues Fruchet 
2688e6441fdeSHugues Fruchet 	fmt->code = ov5640_formats[i].code;
2689e6441fdeSHugues Fruchet 	fmt->colorspace = ov5640_formats[i].colorspace;
2690e6441fdeSHugues Fruchet 	fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
2691e6441fdeSHugues Fruchet 	fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
2692e6441fdeSHugues Fruchet 	fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
2693e3ee691dSHugues Fruchet 
269419a81c14SSteve Longerbeam 	return 0;
269519a81c14SSteve Longerbeam }
269619a81c14SSteve Longerbeam 
26973c28588fSJacopo Mondi static int ov5640_update_pixel_rate(struct ov5640_dev *sensor)
26983c28588fSJacopo Mondi {
26993c28588fSJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
27003c28588fSJacopo Mondi 	enum ov5640_pixel_rate_id pixel_rate_id = mode->pixel_rate;
27013c28588fSJacopo Mondi 	struct v4l2_mbus_framefmt *fmt = &sensor->fmt;
27023c28588fSJacopo Mondi 	unsigned int i = 0;
27033c28588fSJacopo Mondi 	u32 pixel_rate;
27043c28588fSJacopo Mondi 	s64 link_freq;
27053c28588fSJacopo Mondi 	u32 num_lanes;
27063c28588fSJacopo Mondi 	u32 bpp;
27073c28588fSJacopo Mondi 
27083c28588fSJacopo Mondi 	/*
27093c28588fSJacopo Mondi 	 * Update the pixel rate control value.
27103c28588fSJacopo Mondi 	 *
27113c28588fSJacopo Mondi 	 * For DVP mode, maintain the pixel rate calculation using fixed FPS.
27123c28588fSJacopo Mondi 	 */
27133c28588fSJacopo Mondi 	if (!ov5640_is_csi2(sensor)) {
27143c28588fSJacopo Mondi 		__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate,
27153c28588fSJacopo Mondi 					 ov5640_calc_pixel_rate(sensor));
27163c28588fSJacopo Mondi 
27173c28588fSJacopo Mondi 		return 0;
27183c28588fSJacopo Mondi 	}
27193c28588fSJacopo Mondi 
27203c28588fSJacopo Mondi 	/*
27213c28588fSJacopo Mondi 	 * The MIPI CSI-2 link frequency should comply with the CSI-2
27223c28588fSJacopo Mondi 	 * specification and be lower than 1GHz.
27233c28588fSJacopo Mondi 	 *
27243c28588fSJacopo Mondi 	 * Start from the suggested pixel_rate for the current mode and
27253c28588fSJacopo Mondi 	 * progressively slow it down if it exceeds 1GHz.
27263c28588fSJacopo Mondi 	 */
27273c28588fSJacopo Mondi 	num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes;
27283c28588fSJacopo Mondi 	bpp = ov5640_code_to_bpp(fmt->code);
27293c28588fSJacopo Mondi 	do {
27303c28588fSJacopo Mondi 		pixel_rate = ov5640_pixel_rates[pixel_rate_id];
27313c28588fSJacopo Mondi 		link_freq = pixel_rate * bpp / (2 * num_lanes);
27323c28588fSJacopo Mondi 	} while (link_freq >= 1000000000U &&
27333c28588fSJacopo Mondi 		 ++pixel_rate_id < OV5640_NUM_PIXEL_RATES);
27343c28588fSJacopo Mondi 
27353c28588fSJacopo Mondi 	sensor->current_link_freq = link_freq;
27363c28588fSJacopo Mondi 
27373c28588fSJacopo Mondi 	/*
27383c28588fSJacopo Mondi 	 * Higher link rates require the clock tree to be programmed with
27393c28588fSJacopo Mondi 	 * 'mipi_div' = 1; this has the effect of halving the actual output
27403c28588fSJacopo Mondi 	 * pixel rate in the MIPI domain.
27413c28588fSJacopo Mondi 	 *
27423c28588fSJacopo Mondi 	 * Adjust the pixel rate and link frequency control value to report it
27433c28588fSJacopo Mondi 	 * correctly to userspace.
27443c28588fSJacopo Mondi 	 */
27453c28588fSJacopo Mondi 	if (link_freq > OV5640_LINK_RATE_MAX) {
27463c28588fSJacopo Mondi 		pixel_rate /= 2;
27473c28588fSJacopo Mondi 		link_freq /= 2;
27483c28588fSJacopo Mondi 	}
27493c28588fSJacopo Mondi 
27503c28588fSJacopo Mondi 	for (i = 0; i < ARRAY_SIZE(ov5640_csi2_link_freqs); ++i) {
27513c28588fSJacopo Mondi 		if (ov5640_csi2_link_freqs[i] == link_freq)
27523c28588fSJacopo Mondi 			break;
27533c28588fSJacopo Mondi 	}
27543c28588fSJacopo Mondi 	WARN_ON(i == ARRAY_SIZE(ov5640_csi2_link_freqs));
27553c28588fSJacopo Mondi 
27563c28588fSJacopo Mondi 	__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, pixel_rate);
27573c28588fSJacopo Mondi 	__v4l2_ctrl_s_ctrl(sensor->ctrls.link_freq, i);
27583c28588fSJacopo Mondi 
27593c28588fSJacopo Mondi 	return 0;
27603c28588fSJacopo Mondi }
27613c28588fSJacopo Mondi 
276219a81c14SSteve Longerbeam static int ov5640_set_fmt(struct v4l2_subdev *sd,
27630d346d2aSTomi Valkeinen 			  struct v4l2_subdev_state *sd_state,
276419a81c14SSteve Longerbeam 			  struct v4l2_subdev_format *format)
276519a81c14SSteve Longerbeam {
276619a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
276719a81c14SSteve Longerbeam 	const struct ov5640_mode_info *new_mode;
2768e6441fdeSHugues Fruchet 	struct v4l2_mbus_framefmt *mbus_fmt = &format->format;
276919a81c14SSteve Longerbeam 	int ret;
277019a81c14SSteve Longerbeam 
277119a81c14SSteve Longerbeam 	if (format->pad != 0)
277219a81c14SSteve Longerbeam 		return -EINVAL;
277319a81c14SSteve Longerbeam 
277419a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
277519a81c14SSteve Longerbeam 
277619a81c14SSteve Longerbeam 	if (sensor->streaming) {
277719a81c14SSteve Longerbeam 		ret = -EBUSY;
277819a81c14SSteve Longerbeam 		goto out;
277919a81c14SSteve Longerbeam 	}
278019a81c14SSteve Longerbeam 
2781e6441fdeSHugues Fruchet 	ret = ov5640_try_fmt_internal(sd, mbus_fmt,
278219a81c14SSteve Longerbeam 				      sensor->current_fr, &new_mode);
278319a81c14SSteve Longerbeam 	if (ret)
278419a81c14SSteve Longerbeam 		goto out;
278519a81c14SSteve Longerbeam 
2786e738f5ddSMirela Rabulea 	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
2787e738f5ddSMirela Rabulea 		*v4l2_subdev_get_try_format(sd, sd_state, 0) = *mbus_fmt;
2788e738f5ddSMirela Rabulea 		goto out;
2789e738f5ddSMirela Rabulea 	}
279019a81c14SSteve Longerbeam 
27916949d864SHugues Fruchet 	if (new_mode != sensor->current_mode) {
279219a81c14SSteve Longerbeam 		sensor->current_mode = new_mode;
279319a81c14SSteve Longerbeam 		sensor->pending_mode_change = true;
27946949d864SHugues Fruchet 	}
279507115449SJacopo Mondi 	if (mbus_fmt->code != sensor->fmt.code)
2796fb98e29fSHugues Fruchet 		sensor->pending_fmt_change = true;
279707115449SJacopo Mondi 
2798e738f5ddSMirela Rabulea 	/* update format even if code is unchanged, resolution might change */
2799e738f5ddSMirela Rabulea 	sensor->fmt = *mbus_fmt;
2800e738f5ddSMirela Rabulea 
28013c28588fSJacopo Mondi 	ov5640_update_pixel_rate(sensor);
28023c28588fSJacopo Mondi 
280319a81c14SSteve Longerbeam out:
280419a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
280519a81c14SSteve Longerbeam 	return ret;
280619a81c14SSteve Longerbeam }
280719a81c14SSteve Longerbeam 
2808e3ee691dSHugues Fruchet static int ov5640_set_framefmt(struct ov5640_dev *sensor,
2809e3ee691dSHugues Fruchet 			       struct v4l2_mbus_framefmt *format)
2810e3ee691dSHugues Fruchet {
2811e3ee691dSHugues Fruchet 	int ret = 0;
2812d47c4126SHugues Fruchet 	bool is_jpeg = false;
2813b7ed3abdSLoic Poulain 	u8 fmt, mux;
2814e3ee691dSHugues Fruchet 
2815e3ee691dSHugues Fruchet 	switch (format->code) {
28161536fbdbSXavier Roumegue 	case MEDIA_BUS_FMT_UYVY8_1X16:
2817e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_UYVY8_2X8:
2818e3ee691dSHugues Fruchet 		/* YUV422, UYVY */
2819b7ed3abdSLoic Poulain 		fmt = 0x3f;
2820b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_YUV422;
2821e3ee691dSHugues Fruchet 		break;
28221536fbdbSXavier Roumegue 	case MEDIA_BUS_FMT_YUYV8_1X16:
2823e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_YUYV8_2X8:
2824e3ee691dSHugues Fruchet 		/* YUV422, YUYV */
2825b7ed3abdSLoic Poulain 		fmt = 0x30;
2826b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_YUV422;
2827e3ee691dSHugues Fruchet 		break;
2828e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_RGB565_2X8_LE:
2829e3ee691dSHugues Fruchet 		/* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */
2830b7ed3abdSLoic Poulain 		fmt = 0x6F;
2831b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RGB;
2832e3ee691dSHugues Fruchet 		break;
2833e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_RGB565_2X8_BE:
2834e3ee691dSHugues Fruchet 		/* RGB565 {r[4:0],g[5:3]},{g[2:0],b[4:0]} */
2835b7ed3abdSLoic Poulain 		fmt = 0x61;
2836b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RGB;
2837e3ee691dSHugues Fruchet 		break;
2838d47c4126SHugues Fruchet 	case MEDIA_BUS_FMT_JPEG_1X8:
2839d47c4126SHugues Fruchet 		/* YUV422, YUYV */
2840b7ed3abdSLoic Poulain 		fmt = 0x30;
2841b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_YUV422;
2842d47c4126SHugues Fruchet 		is_jpeg = true;
2843d47c4126SHugues Fruchet 		break;
2844b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SBGGR8_1X8:
2845b7ed3abdSLoic Poulain 		/* Raw, BGBG... / GRGR... */
2846b7ed3abdSLoic Poulain 		fmt = 0x00;
2847b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2848b7ed3abdSLoic Poulain 		break;
2849b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SGBRG8_1X8:
2850b7ed3abdSLoic Poulain 		/* Raw bayer, GBGB... / RGRG... */
2851b7ed3abdSLoic Poulain 		fmt = 0x01;
2852b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2853b7ed3abdSLoic Poulain 		break;
2854b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SGRBG8_1X8:
2855b7ed3abdSLoic Poulain 		/* Raw bayer, GRGR... / BGBG... */
2856b7ed3abdSLoic Poulain 		fmt = 0x02;
2857b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2858b7ed3abdSLoic Poulain 		break;
2859b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SRGGB8_1X8:
2860b7ed3abdSLoic Poulain 		/* Raw bayer, RGRG... / GBGB... */
2861b7ed3abdSLoic Poulain 		fmt = 0x03;
2862b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2863b7ed3abdSLoic Poulain 		break;
2864e3ee691dSHugues Fruchet 	default:
2865e3ee691dSHugues Fruchet 		return -EINVAL;
2866e3ee691dSHugues Fruchet 	}
2867e3ee691dSHugues Fruchet 
2868e3ee691dSHugues Fruchet 	/* FORMAT CONTROL00: YUV and RGB formatting */
2869b7ed3abdSLoic Poulain 	ret = ov5640_write_reg(sensor, OV5640_REG_FORMAT_CONTROL00, fmt);
2870e3ee691dSHugues Fruchet 	if (ret)
2871e3ee691dSHugues Fruchet 		return ret;
2872e3ee691dSHugues Fruchet 
2873e3ee691dSHugues Fruchet 	/* FORMAT MUX CONTROL: ISP YUV or RGB */
2874b7ed3abdSLoic Poulain 	ret = ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL, mux);
2875d47c4126SHugues Fruchet 	if (ret)
2876d47c4126SHugues Fruchet 		return ret;
2877d47c4126SHugues Fruchet 
2878d47c4126SHugues Fruchet 	/*
2879d47c4126SHugues Fruchet 	 * TIMING TC REG21:
2880d47c4126SHugues Fruchet 	 * - [5]:	JPEG enable
2881d47c4126SHugues Fruchet 	 */
2882d47c4126SHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
2883d47c4126SHugues Fruchet 			     BIT(5), is_jpeg ? BIT(5) : 0);
2884d47c4126SHugues Fruchet 	if (ret)
2885d47c4126SHugues Fruchet 		return ret;
2886d47c4126SHugues Fruchet 
2887d47c4126SHugues Fruchet 	/*
2888d47c4126SHugues Fruchet 	 * SYSTEM RESET02:
2889d47c4126SHugues Fruchet 	 * - [4]:	Reset JFIFO
2890d47c4126SHugues Fruchet 	 * - [3]:	Reset SFIFO
2891d47c4126SHugues Fruchet 	 * - [2]:	Reset JPEG
2892d47c4126SHugues Fruchet 	 */
2893d47c4126SHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_RESET02,
2894d47c4126SHugues Fruchet 			     BIT(4) | BIT(3) | BIT(2),
2895d47c4126SHugues Fruchet 			     is_jpeg ? 0 : (BIT(4) | BIT(3) | BIT(2)));
2896d47c4126SHugues Fruchet 	if (ret)
2897d47c4126SHugues Fruchet 		return ret;
2898d47c4126SHugues Fruchet 
2899d47c4126SHugues Fruchet 	/*
2900d47c4126SHugues Fruchet 	 * CLOCK ENABLE02:
2901d47c4126SHugues Fruchet 	 * - [5]:	Enable JPEG 2x clock
2902d47c4126SHugues Fruchet 	 * - [3]:	Enable JPEG clock
2903d47c4126SHugues Fruchet 	 */
2904d47c4126SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_SYS_CLOCK_ENABLE02,
2905d47c4126SHugues Fruchet 			      BIT(5) | BIT(3),
2906d47c4126SHugues Fruchet 			      is_jpeg ? (BIT(5) | BIT(3)) : 0);
2907e3ee691dSHugues Fruchet }
290819a81c14SSteve Longerbeam 
290919a81c14SSteve Longerbeam /*
291019a81c14SSteve Longerbeam  * Sensor Controls.
291119a81c14SSteve Longerbeam  */
291219a81c14SSteve Longerbeam 
291319a81c14SSteve Longerbeam static int ov5640_set_ctrl_hue(struct ov5640_dev *sensor, int value)
291419a81c14SSteve Longerbeam {
291519a81c14SSteve Longerbeam 	int ret;
291619a81c14SSteve Longerbeam 
291719a81c14SSteve Longerbeam 	if (value) {
291819a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
291919a81c14SSteve Longerbeam 				     BIT(0), BIT(0));
292019a81c14SSteve Longerbeam 		if (ret)
292119a81c14SSteve Longerbeam 			return ret;
292219a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_SDE_CTRL1, value);
292319a81c14SSteve Longerbeam 	} else {
292419a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(0), 0);
292519a81c14SSteve Longerbeam 	}
292619a81c14SSteve Longerbeam 
292719a81c14SSteve Longerbeam 	return ret;
292819a81c14SSteve Longerbeam }
292919a81c14SSteve Longerbeam 
293019a81c14SSteve Longerbeam static int ov5640_set_ctrl_contrast(struct ov5640_dev *sensor, int value)
293119a81c14SSteve Longerbeam {
293219a81c14SSteve Longerbeam 	int ret;
293319a81c14SSteve Longerbeam 
293419a81c14SSteve Longerbeam 	if (value) {
293519a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
293619a81c14SSteve Longerbeam 				     BIT(2), BIT(2));
293719a81c14SSteve Longerbeam 		if (ret)
293819a81c14SSteve Longerbeam 			return ret;
293919a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL5,
294019a81c14SSteve Longerbeam 				       value & 0xff);
294119a81c14SSteve Longerbeam 	} else {
294219a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(2), 0);
294319a81c14SSteve Longerbeam 	}
294419a81c14SSteve Longerbeam 
294519a81c14SSteve Longerbeam 	return ret;
294619a81c14SSteve Longerbeam }
294719a81c14SSteve Longerbeam 
294819a81c14SSteve Longerbeam static int ov5640_set_ctrl_saturation(struct ov5640_dev *sensor, int value)
294919a81c14SSteve Longerbeam {
295019a81c14SSteve Longerbeam 	int ret;
295119a81c14SSteve Longerbeam 
295219a81c14SSteve Longerbeam 	if (value) {
295319a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
295419a81c14SSteve Longerbeam 				     BIT(1), BIT(1));
295519a81c14SSteve Longerbeam 		if (ret)
295619a81c14SSteve Longerbeam 			return ret;
295719a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL3,
295819a81c14SSteve Longerbeam 				       value & 0xff);
295919a81c14SSteve Longerbeam 		if (ret)
296019a81c14SSteve Longerbeam 			return ret;
296119a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL4,
296219a81c14SSteve Longerbeam 				       value & 0xff);
296319a81c14SSteve Longerbeam 	} else {
296419a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(1), 0);
296519a81c14SSteve Longerbeam 	}
296619a81c14SSteve Longerbeam 
296719a81c14SSteve Longerbeam 	return ret;
296819a81c14SSteve Longerbeam }
296919a81c14SSteve Longerbeam 
297019a81c14SSteve Longerbeam static int ov5640_set_ctrl_white_balance(struct ov5640_dev *sensor, int awb)
297119a81c14SSteve Longerbeam {
297219a81c14SSteve Longerbeam 	int ret;
297319a81c14SSteve Longerbeam 
297419a81c14SSteve Longerbeam 	ret = ov5640_mod_reg(sensor, OV5640_REG_AWB_MANUAL_CTRL,
297519a81c14SSteve Longerbeam 			     BIT(0), awb ? 0 : 1);
297619a81c14SSteve Longerbeam 	if (ret)
297719a81c14SSteve Longerbeam 		return ret;
297819a81c14SSteve Longerbeam 
297919a81c14SSteve Longerbeam 	if (!awb) {
298019a81c14SSteve Longerbeam 		u16 red = (u16)sensor->ctrls.red_balance->val;
298119a81c14SSteve Longerbeam 		u16 blue = (u16)sensor->ctrls.blue_balance->val;
298219a81c14SSteve Longerbeam 
298319a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_R_GAIN, red);
298419a81c14SSteve Longerbeam 		if (ret)
298519a81c14SSteve Longerbeam 			return ret;
298619a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_B_GAIN, blue);
298719a81c14SSteve Longerbeam 	}
298819a81c14SSteve Longerbeam 
298919a81c14SSteve Longerbeam 	return ret;
299019a81c14SSteve Longerbeam }
299119a81c14SSteve Longerbeam 
29923cca8ef5SHugues Fruchet static int ov5640_set_ctrl_exposure(struct ov5640_dev *sensor,
29933cca8ef5SHugues Fruchet 				    enum v4l2_exposure_auto_type auto_exposure)
299419a81c14SSteve Longerbeam {
299519a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
29963cca8ef5SHugues Fruchet 	bool auto_exp = (auto_exposure == V4L2_EXPOSURE_AUTO);
299719a81c14SSteve Longerbeam 	int ret = 0;
299819a81c14SSteve Longerbeam 
299919a81c14SSteve Longerbeam 	if (ctrls->auto_exp->is_new) {
30003cca8ef5SHugues Fruchet 		ret = ov5640_set_autoexposure(sensor, auto_exp);
300119a81c14SSteve Longerbeam 		if (ret)
300219a81c14SSteve Longerbeam 			return ret;
300319a81c14SSteve Longerbeam 	}
300419a81c14SSteve Longerbeam 
30053cca8ef5SHugues Fruchet 	if (!auto_exp && ctrls->exposure->is_new) {
300619a81c14SSteve Longerbeam 		u16 max_exp;
300719a81c14SSteve Longerbeam 
300819a81c14SSteve Longerbeam 		ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_VTS,
300919a81c14SSteve Longerbeam 					&max_exp);
301019a81c14SSteve Longerbeam 		if (ret)
301119a81c14SSteve Longerbeam 			return ret;
301219a81c14SSteve Longerbeam 		ret = ov5640_get_vts(sensor);
301319a81c14SSteve Longerbeam 		if (ret < 0)
301419a81c14SSteve Longerbeam 			return ret;
301519a81c14SSteve Longerbeam 		max_exp += ret;
30166146fde3SHugues Fruchet 		ret = 0;
301719a81c14SSteve Longerbeam 
301819a81c14SSteve Longerbeam 		if (ctrls->exposure->val < max_exp)
301919a81c14SSteve Longerbeam 			ret = ov5640_set_exposure(sensor, ctrls->exposure->val);
302019a81c14SSteve Longerbeam 	}
302119a81c14SSteve Longerbeam 
302219a81c14SSteve Longerbeam 	return ret;
302319a81c14SSteve Longerbeam }
302419a81c14SSteve Longerbeam 
30253cca8ef5SHugues Fruchet static int ov5640_set_ctrl_gain(struct ov5640_dev *sensor, bool auto_gain)
302619a81c14SSteve Longerbeam {
302719a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
302819a81c14SSteve Longerbeam 	int ret = 0;
302919a81c14SSteve Longerbeam 
303019a81c14SSteve Longerbeam 	if (ctrls->auto_gain->is_new) {
30313cca8ef5SHugues Fruchet 		ret = ov5640_set_autogain(sensor, auto_gain);
303219a81c14SSteve Longerbeam 		if (ret)
303319a81c14SSteve Longerbeam 			return ret;
303419a81c14SSteve Longerbeam 	}
303519a81c14SSteve Longerbeam 
30363cca8ef5SHugues Fruchet 	if (!auto_gain && ctrls->gain->is_new)
30373cca8ef5SHugues Fruchet 		ret = ov5640_set_gain(sensor, ctrls->gain->val);
303819a81c14SSteve Longerbeam 
303919a81c14SSteve Longerbeam 	return ret;
304019a81c14SSteve Longerbeam }
304119a81c14SSteve Longerbeam 
30429f6d7bacSChen-Yu Tsai static const char * const test_pattern_menu[] = {
30439f6d7bacSChen-Yu Tsai 	"Disabled",
30449f6d7bacSChen-Yu Tsai 	"Color bars",
3045bddc5cdfSChen-Yu Tsai 	"Color bars w/ rolling bar",
3046bddc5cdfSChen-Yu Tsai 	"Color squares",
3047bddc5cdfSChen-Yu Tsai 	"Color squares w/ rolling bar",
30489f6d7bacSChen-Yu Tsai };
30499f6d7bacSChen-Yu Tsai 
3050a0c29afbSChen-Yu Tsai #define OV5640_TEST_ENABLE		BIT(7)
3051a0c29afbSChen-Yu Tsai #define OV5640_TEST_ROLLING		BIT(6)	/* rolling horizontal bar */
3052a0c29afbSChen-Yu Tsai #define OV5640_TEST_TRANSPARENT		BIT(5)
3053a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE_BW		BIT(4)	/* black & white squares */
3054a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_STANDARD	(0 << 2)
3055a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_1	(1 << 2)
3056a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_HOR_CHANGE	(2 << 2)
3057a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_2	(3 << 2)
3058a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR			(0 << 0)
3059a0c29afbSChen-Yu Tsai #define OV5640_TEST_RANDOM		(1 << 0)
3060a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE		(2 << 0)
3061a0c29afbSChen-Yu Tsai #define OV5640_TEST_BLACK		(3 << 0)
3062a0c29afbSChen-Yu Tsai 
3063a0c29afbSChen-Yu Tsai static const u8 test_pattern_val[] = {
3064a0c29afbSChen-Yu Tsai 	0,
30652aff1fc3SChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_BAR_VERT_CHANGE_1 |
3066a0c29afbSChen-Yu Tsai 		OV5640_TEST_BAR,
3067bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_ROLLING |
3068bddc5cdfSChen-Yu Tsai 		OV5640_TEST_BAR_VERT_CHANGE_1 | OV5640_TEST_BAR,
3069bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_SQUARE,
3070bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_ROLLING | OV5640_TEST_SQUARE,
3071a0c29afbSChen-Yu Tsai };
3072a0c29afbSChen-Yu Tsai 
307319a81c14SSteve Longerbeam static int ov5640_set_ctrl_test_pattern(struct ov5640_dev *sensor, int value)
307419a81c14SSteve Longerbeam {
3075a0c29afbSChen-Yu Tsai 	return ov5640_write_reg(sensor, OV5640_REG_PRE_ISP_TEST_SET1,
3076a0c29afbSChen-Yu Tsai 				test_pattern_val[value]);
307719a81c14SSteve Longerbeam }
307819a81c14SSteve Longerbeam 
30791068fecaSMylène Josserand static int ov5640_set_ctrl_light_freq(struct ov5640_dev *sensor, int value)
30801068fecaSMylène Josserand {
30811068fecaSMylène Josserand 	int ret;
30821068fecaSMylène Josserand 
30831068fecaSMylène Josserand 	ret = ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL01, BIT(7),
30841068fecaSMylène Josserand 			     (value == V4L2_CID_POWER_LINE_FREQUENCY_AUTO) ?
30851068fecaSMylène Josserand 			     0 : BIT(7));
30861068fecaSMylène Josserand 	if (ret)
30871068fecaSMylène Josserand 		return ret;
30881068fecaSMylène Josserand 
30891068fecaSMylène Josserand 	return ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL00, BIT(2),
30901068fecaSMylène Josserand 			      (value == V4L2_CID_POWER_LINE_FREQUENCY_50HZ) ?
30911068fecaSMylène Josserand 			      BIT(2) : 0);
30921068fecaSMylène Josserand }
30931068fecaSMylène Josserand 
3094ce85705aSHugues Fruchet static int ov5640_set_ctrl_hflip(struct ov5640_dev *sensor, int value)
3095ce85705aSHugues Fruchet {
3096ce85705aSHugues Fruchet 	/*
3097c3f3ba3eSHugues Fruchet 	 * If sensor is mounted upside down, mirror logic is inversed.
3098c3f3ba3eSHugues Fruchet 	 *
3099ce85705aSHugues Fruchet 	 * Sensor is a BSI (Back Side Illuminated) one,
3100ce85705aSHugues Fruchet 	 * so image captured is physically mirrored.
3101ce85705aSHugues Fruchet 	 * This is why mirror logic is inversed in
3102ce85705aSHugues Fruchet 	 * order to cancel this mirror effect.
3103ce85705aSHugues Fruchet 	 */
3104ce85705aSHugues Fruchet 
3105ce85705aSHugues Fruchet 	/*
3106ce85705aSHugues Fruchet 	 * TIMING TC REG21:
3107ce85705aSHugues Fruchet 	 * - [2]:	ISP mirror
3108ce85705aSHugues Fruchet 	 * - [1]:	Sensor mirror
3109ce85705aSHugues Fruchet 	 */
3110ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
3111ce85705aSHugues Fruchet 			      BIT(2) | BIT(1),
3112c3f3ba3eSHugues Fruchet 			      (!(value ^ sensor->upside_down)) ?
3113c3f3ba3eSHugues Fruchet 			      (BIT(2) | BIT(1)) : 0);
3114ce85705aSHugues Fruchet }
3115ce85705aSHugues Fruchet 
3116ce85705aSHugues Fruchet static int ov5640_set_ctrl_vflip(struct ov5640_dev *sensor, int value)
3117ce85705aSHugues Fruchet {
3118c3f3ba3eSHugues Fruchet 	/* If sensor is mounted upside down, flip logic is inversed */
3119c3f3ba3eSHugues Fruchet 
3120ce85705aSHugues Fruchet 	/*
3121ce85705aSHugues Fruchet 	 * TIMING TC REG20:
3122ce85705aSHugues Fruchet 	 * - [2]:	ISP vflip
3123ce85705aSHugues Fruchet 	 * - [1]:	Sensor vflip
3124ce85705aSHugues Fruchet 	 */
3125ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20,
3126ce85705aSHugues Fruchet 			      BIT(2) | BIT(1),
3127c3f3ba3eSHugues Fruchet 			      (value ^ sensor->upside_down) ?
3128c3f3ba3eSHugues Fruchet 			      (BIT(2) | BIT(1)) : 0);
3129ce85705aSHugues Fruchet }
3130ce85705aSHugues Fruchet 
313119a81c14SSteve Longerbeam static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
313219a81c14SSteve Longerbeam {
313319a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
313419a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
313519a81c14SSteve Longerbeam 	int val;
313619a81c14SSteve Longerbeam 
313719a81c14SSteve Longerbeam 	/* v4l2_ctrl_lock() locks our own mutex */
313819a81c14SSteve Longerbeam 
313919a81c14SSteve Longerbeam 	switch (ctrl->id) {
314019a81c14SSteve Longerbeam 	case V4L2_CID_AUTOGAIN:
314119a81c14SSteve Longerbeam 		val = ov5640_get_gain(sensor);
314219a81c14SSteve Longerbeam 		if (val < 0)
314319a81c14SSteve Longerbeam 			return val;
314419a81c14SSteve Longerbeam 		sensor->ctrls.gain->val = val;
314519a81c14SSteve Longerbeam 		break;
314619a81c14SSteve Longerbeam 	case V4L2_CID_EXPOSURE_AUTO:
314719a81c14SSteve Longerbeam 		val = ov5640_get_exposure(sensor);
314819a81c14SSteve Longerbeam 		if (val < 0)
314919a81c14SSteve Longerbeam 			return val;
315019a81c14SSteve Longerbeam 		sensor->ctrls.exposure->val = val;
315119a81c14SSteve Longerbeam 		break;
315219a81c14SSteve Longerbeam 	}
315319a81c14SSteve Longerbeam 
315419a81c14SSteve Longerbeam 	return 0;
315519a81c14SSteve Longerbeam }
315619a81c14SSteve Longerbeam 
315719a81c14SSteve Longerbeam static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl)
315819a81c14SSteve Longerbeam {
315919a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
316019a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
316119a81c14SSteve Longerbeam 	int ret;
316219a81c14SSteve Longerbeam 
316319a81c14SSteve Longerbeam 	/* v4l2_ctrl_lock() locks our own mutex */
316419a81c14SSteve Longerbeam 
316519a81c14SSteve Longerbeam 	/*
316619a81c14SSteve Longerbeam 	 * If the device is not powered up by the host driver do
316719a81c14SSteve Longerbeam 	 * not apply any controls to H/W at this time. Instead
316819a81c14SSteve Longerbeam 	 * the controls will be restored right after power-up.
316919a81c14SSteve Longerbeam 	 */
317019a81c14SSteve Longerbeam 	if (sensor->power_count == 0)
317119a81c14SSteve Longerbeam 		return 0;
317219a81c14SSteve Longerbeam 
317319a81c14SSteve Longerbeam 	switch (ctrl->id) {
317419a81c14SSteve Longerbeam 	case V4L2_CID_AUTOGAIN:
317519a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_gain(sensor, ctrl->val);
317619a81c14SSteve Longerbeam 		break;
317719a81c14SSteve Longerbeam 	case V4L2_CID_EXPOSURE_AUTO:
317819a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_exposure(sensor, ctrl->val);
317919a81c14SSteve Longerbeam 		break;
318019a81c14SSteve Longerbeam 	case V4L2_CID_AUTO_WHITE_BALANCE:
318119a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_white_balance(sensor, ctrl->val);
318219a81c14SSteve Longerbeam 		break;
318319a81c14SSteve Longerbeam 	case V4L2_CID_HUE:
318419a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_hue(sensor, ctrl->val);
318519a81c14SSteve Longerbeam 		break;
318619a81c14SSteve Longerbeam 	case V4L2_CID_CONTRAST:
318719a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_contrast(sensor, ctrl->val);
318819a81c14SSteve Longerbeam 		break;
318919a81c14SSteve Longerbeam 	case V4L2_CID_SATURATION:
319019a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_saturation(sensor, ctrl->val);
319119a81c14SSteve Longerbeam 		break;
319219a81c14SSteve Longerbeam 	case V4L2_CID_TEST_PATTERN:
319319a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_test_pattern(sensor, ctrl->val);
319419a81c14SSteve Longerbeam 		break;
31951068fecaSMylène Josserand 	case V4L2_CID_POWER_LINE_FREQUENCY:
31961068fecaSMylène Josserand 		ret = ov5640_set_ctrl_light_freq(sensor, ctrl->val);
31971068fecaSMylène Josserand 		break;
3198ce85705aSHugues Fruchet 	case V4L2_CID_HFLIP:
3199ce85705aSHugues Fruchet 		ret = ov5640_set_ctrl_hflip(sensor, ctrl->val);
3200ce85705aSHugues Fruchet 		break;
3201ce85705aSHugues Fruchet 	case V4L2_CID_VFLIP:
3202ce85705aSHugues Fruchet 		ret = ov5640_set_ctrl_vflip(sensor, ctrl->val);
3203ce85705aSHugues Fruchet 		break;
320419a81c14SSteve Longerbeam 	default:
320519a81c14SSteve Longerbeam 		ret = -EINVAL;
320619a81c14SSteve Longerbeam 		break;
320719a81c14SSteve Longerbeam 	}
320819a81c14SSteve Longerbeam 
320919a81c14SSteve Longerbeam 	return ret;
321019a81c14SSteve Longerbeam }
321119a81c14SSteve Longerbeam 
321219a81c14SSteve Longerbeam static const struct v4l2_ctrl_ops ov5640_ctrl_ops = {
321319a81c14SSteve Longerbeam 	.g_volatile_ctrl = ov5640_g_volatile_ctrl,
321419a81c14SSteve Longerbeam 	.s_ctrl = ov5640_s_ctrl,
321519a81c14SSteve Longerbeam };
321619a81c14SSteve Longerbeam 
321719a81c14SSteve Longerbeam static int ov5640_init_controls(struct ov5640_dev *sensor)
321819a81c14SSteve Longerbeam {
321922845bf2SJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
322019a81c14SSteve Longerbeam 	const struct v4l2_ctrl_ops *ops = &ov5640_ctrl_ops;
322119a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
322219a81c14SSteve Longerbeam 	struct v4l2_ctrl_handler *hdl = &ctrls->handler;
322319a81c14SSteve Longerbeam 	int ret;
322419a81c14SSteve Longerbeam 
322519a81c14SSteve Longerbeam 	v4l2_ctrl_handler_init(hdl, 32);
322619a81c14SSteve Longerbeam 
322719a81c14SSteve Longerbeam 	/* we can use our own mutex for the ctrl lock */
322819a81c14SSteve Longerbeam 	hdl->lock = &sensor->lock;
322919a81c14SSteve Longerbeam 
3230cc196e48SBenoit Parrot 	/* Clock related controls */
3231cc196e48SBenoit Parrot 	ctrls->pixel_rate = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE,
323222845bf2SJacopo Mondi 			      ov5640_pixel_rates[OV5640_NUM_PIXEL_RATES - 1],
323322845bf2SJacopo Mondi 			      ov5640_pixel_rates[0], 1,
323422845bf2SJacopo Mondi 			      ov5640_pixel_rates[mode->pixel_rate]);
3235cc196e48SBenoit Parrot 
32367a3b8d4bSJacopo Mondi 	ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops,
32377a3b8d4bSJacopo Mondi 					V4L2_CID_LINK_FREQ,
32387a3b8d4bSJacopo Mondi 					ARRAY_SIZE(ov5640_csi2_link_freqs) - 1,
32397a3b8d4bSJacopo Mondi 					OV5640_DEFAULT_LINK_FREQ,
32407a3b8d4bSJacopo Mondi 					ov5640_csi2_link_freqs);
32417a3b8d4bSJacopo Mondi 
324219a81c14SSteve Longerbeam 	/* Auto/manual white balance */
324319a81c14SSteve Longerbeam 	ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops,
324419a81c14SSteve Longerbeam 					   V4L2_CID_AUTO_WHITE_BALANCE,
324519a81c14SSteve Longerbeam 					   0, 1, 1, 1);
324619a81c14SSteve Longerbeam 	ctrls->blue_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BLUE_BALANCE,
324719a81c14SSteve Longerbeam 						0, 4095, 1, 0);
324819a81c14SSteve Longerbeam 	ctrls->red_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_RED_BALANCE,
324919a81c14SSteve Longerbeam 					       0, 4095, 1, 0);
325019a81c14SSteve Longerbeam 	/* Auto/manual exposure */
325119a81c14SSteve Longerbeam 	ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops,
325219a81c14SSteve Longerbeam 						 V4L2_CID_EXPOSURE_AUTO,
325319a81c14SSteve Longerbeam 						 V4L2_EXPOSURE_MANUAL, 0,
325419a81c14SSteve Longerbeam 						 V4L2_EXPOSURE_AUTO);
325519a81c14SSteve Longerbeam 	ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
325619a81c14SSteve Longerbeam 					    0, 65535, 1, 0);
325719a81c14SSteve Longerbeam 	/* Auto/manual gain */
325819a81c14SSteve Longerbeam 	ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN,
325919a81c14SSteve Longerbeam 					     0, 1, 1, 1);
326019a81c14SSteve Longerbeam 	ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN,
326119a81c14SSteve Longerbeam 					0, 1023, 1, 0);
326219a81c14SSteve Longerbeam 
326319a81c14SSteve Longerbeam 	ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION,
326419a81c14SSteve Longerbeam 					      0, 255, 1, 64);
326519a81c14SSteve Longerbeam 	ctrls->hue = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HUE,
326619a81c14SSteve Longerbeam 				       0, 359, 1, 0);
326719a81c14SSteve Longerbeam 	ctrls->contrast = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST,
326819a81c14SSteve Longerbeam 					    0, 255, 1, 0);
326919a81c14SSteve Longerbeam 	ctrls->test_pattern =
327019a81c14SSteve Longerbeam 		v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN,
327119a81c14SSteve Longerbeam 					     ARRAY_SIZE(test_pattern_menu) - 1,
327219a81c14SSteve Longerbeam 					     0, 0, test_pattern_menu);
3273ce85705aSHugues Fruchet 	ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP,
3274ce85705aSHugues Fruchet 					 0, 1, 1, 0);
3275ce85705aSHugues Fruchet 	ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP,
3276ce85705aSHugues Fruchet 					 0, 1, 1, 0);
327719a81c14SSteve Longerbeam 
32781068fecaSMylène Josserand 	ctrls->light_freq =
32791068fecaSMylène Josserand 		v4l2_ctrl_new_std_menu(hdl, ops,
32801068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY,
32811068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
32821068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
32831068fecaSMylène Josserand 
328419a81c14SSteve Longerbeam 	if (hdl->error) {
328519a81c14SSteve Longerbeam 		ret = hdl->error;
328619a81c14SSteve Longerbeam 		goto free_ctrls;
328719a81c14SSteve Longerbeam 	}
328819a81c14SSteve Longerbeam 
3289cc196e48SBenoit Parrot 	ctrls->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY;
32907a3b8d4bSJacopo Mondi 	ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
329119a81c14SSteve Longerbeam 	ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE;
329219a81c14SSteve Longerbeam 	ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE;
329319a81c14SSteve Longerbeam 
329419a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false);
329519a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(2, &ctrls->auto_gain, 0, true);
329619a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(2, &ctrls->auto_exp, 1, true);
329719a81c14SSteve Longerbeam 
329819a81c14SSteve Longerbeam 	sensor->sd.ctrl_handler = hdl;
329919a81c14SSteve Longerbeam 	return 0;
330019a81c14SSteve Longerbeam 
330119a81c14SSteve Longerbeam free_ctrls:
330219a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(hdl);
330319a81c14SSteve Longerbeam 	return ret;
330419a81c14SSteve Longerbeam }
330519a81c14SSteve Longerbeam 
330619a81c14SSteve Longerbeam static int ov5640_enum_frame_size(struct v4l2_subdev *sd,
33070d346d2aSTomi Valkeinen 				  struct v4l2_subdev_state *sd_state,
330819a81c14SSteve Longerbeam 				  struct v4l2_subdev_frame_size_enum *fse)
330919a81c14SSteve Longerbeam {
331019a81c14SSteve Longerbeam 	if (fse->pad != 0)
331119a81c14SSteve Longerbeam 		return -EINVAL;
331219a81c14SSteve Longerbeam 	if (fse->index >= OV5640_NUM_MODES)
331319a81c14SSteve Longerbeam 		return -EINVAL;
331419a81c14SSteve Longerbeam 
33155113d5b3SJacopo Mondi 	fse->min_width = ov5640_mode_data[fse->index].width;
331641d8d7f5SHugues Fruchet 	fse->max_width = fse->min_width;
33175113d5b3SJacopo Mondi 	fse->min_height = ov5640_mode_data[fse->index].height;
331841d8d7f5SHugues Fruchet 	fse->max_height = fse->min_height;
331919a81c14SSteve Longerbeam 
332019a81c14SSteve Longerbeam 	return 0;
332119a81c14SSteve Longerbeam }
332219a81c14SSteve Longerbeam 
332319a81c14SSteve Longerbeam static int ov5640_enum_frame_interval(
332419a81c14SSteve Longerbeam 	struct v4l2_subdev *sd,
33250d346d2aSTomi Valkeinen 	struct v4l2_subdev_state *sd_state,
332619a81c14SSteve Longerbeam 	struct v4l2_subdev_frame_interval_enum *fie)
332719a81c14SSteve Longerbeam {
332819a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
332919a81c14SSteve Longerbeam 	struct v4l2_fract tpf;
333019a81c14SSteve Longerbeam 	int ret;
333119a81c14SSteve Longerbeam 
333219a81c14SSteve Longerbeam 	if (fie->pad != 0)
333319a81c14SSteve Longerbeam 		return -EINVAL;
333419a81c14SSteve Longerbeam 	if (fie->index >= OV5640_NUM_FRAMERATES)
333519a81c14SSteve Longerbeam 		return -EINVAL;
333619a81c14SSteve Longerbeam 
333719a81c14SSteve Longerbeam 	tpf.numerator = 1;
333819a81c14SSteve Longerbeam 	tpf.denominator = ov5640_framerates[fie->index];
333919a81c14SSteve Longerbeam 
334019a81c14SSteve Longerbeam 	ret = ov5640_try_frame_interval(sensor, &tpf,
334119a81c14SSteve Longerbeam 					fie->width, fie->height);
334219a81c14SSteve Longerbeam 	if (ret < 0)
334319a81c14SSteve Longerbeam 		return -EINVAL;
334419a81c14SSteve Longerbeam 
334519a81c14SSteve Longerbeam 	fie->interval = tpf;
334619a81c14SSteve Longerbeam 	return 0;
334719a81c14SSteve Longerbeam }
334819a81c14SSteve Longerbeam 
334919a81c14SSteve Longerbeam static int ov5640_g_frame_interval(struct v4l2_subdev *sd,
335019a81c14SSteve Longerbeam 				   struct v4l2_subdev_frame_interval *fi)
335119a81c14SSteve Longerbeam {
335219a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
335319a81c14SSteve Longerbeam 
335419a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
335519a81c14SSteve Longerbeam 	fi->interval = sensor->frame_interval;
335619a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
335719a81c14SSteve Longerbeam 
335819a81c14SSteve Longerbeam 	return 0;
335919a81c14SSteve Longerbeam }
336019a81c14SSteve Longerbeam 
336119a81c14SSteve Longerbeam static int ov5640_s_frame_interval(struct v4l2_subdev *sd,
336219a81c14SSteve Longerbeam 				   struct v4l2_subdev_frame_interval *fi)
336319a81c14SSteve Longerbeam {
336419a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
336519a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
336619a81c14SSteve Longerbeam 	int frame_rate, ret = 0;
336719a81c14SSteve Longerbeam 
336819a81c14SSteve Longerbeam 	if (fi->pad != 0)
336919a81c14SSteve Longerbeam 		return -EINVAL;
337019a81c14SSteve Longerbeam 
337119a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
337219a81c14SSteve Longerbeam 
337319a81c14SSteve Longerbeam 	if (sensor->streaming) {
337419a81c14SSteve Longerbeam 		ret = -EBUSY;
337519a81c14SSteve Longerbeam 		goto out;
337619a81c14SSteve Longerbeam 	}
337719a81c14SSteve Longerbeam 
337819a81c14SSteve Longerbeam 	mode = sensor->current_mode;
337919a81c14SSteve Longerbeam 
338019a81c14SSteve Longerbeam 	frame_rate = ov5640_try_frame_interval(sensor, &fi->interval,
33815113d5b3SJacopo Mondi 					       mode->width,
33825113d5b3SJacopo Mondi 					       mode->height);
3383e823fb16SMaxime Ripard 	if (frame_rate < 0) {
3384e823fb16SMaxime Ripard 		/* Always return a valid frame interval value */
3385e823fb16SMaxime Ripard 		fi->interval = sensor->frame_interval;
3386e823fb16SMaxime Ripard 		goto out;
3387e823fb16SMaxime Ripard 	}
338819a81c14SSteve Longerbeam 
33895113d5b3SJacopo Mondi 	mode = ov5640_find_mode(sensor, frame_rate, mode->width,
33905113d5b3SJacopo Mondi 				mode->height, true);
33913c4a7372SHugues Fruchet 	if (!mode) {
33923c4a7372SHugues Fruchet 		ret = -EINVAL;
33933c4a7372SHugues Fruchet 		goto out;
33943c4a7372SHugues Fruchet 	}
33953c4a7372SHugues Fruchet 
33960929983eSHugues Fruchet 	if (mode != sensor->current_mode ||
33970929983eSHugues Fruchet 	    frame_rate != sensor->current_fr) {
33980929983eSHugues Fruchet 		sensor->current_fr = frame_rate;
33990929983eSHugues Fruchet 		sensor->frame_interval = fi->interval;
34003c4a7372SHugues Fruchet 		sensor->current_mode = mode;
340119a81c14SSteve Longerbeam 		sensor->pending_mode_change = true;
3402cc196e48SBenoit Parrot 
3403cc196e48SBenoit Parrot 		__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate,
3404cc196e48SBenoit Parrot 					 ov5640_calc_pixel_rate(sensor));
34056949d864SHugues Fruchet 	}
340619a81c14SSteve Longerbeam out:
340719a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
340819a81c14SSteve Longerbeam 	return ret;
340919a81c14SSteve Longerbeam }
341019a81c14SSteve Longerbeam 
341119a81c14SSteve Longerbeam static int ov5640_enum_mbus_code(struct v4l2_subdev *sd,
34120d346d2aSTomi Valkeinen 				 struct v4l2_subdev_state *sd_state,
341319a81c14SSteve Longerbeam 				 struct v4l2_subdev_mbus_code_enum *code)
341419a81c14SSteve Longerbeam {
341519a81c14SSteve Longerbeam 	if (code->pad != 0)
341619a81c14SSteve Longerbeam 		return -EINVAL;
3417e3ee691dSHugues Fruchet 	if (code->index >= ARRAY_SIZE(ov5640_formats))
341819a81c14SSteve Longerbeam 		return -EINVAL;
341919a81c14SSteve Longerbeam 
3420e3ee691dSHugues Fruchet 	code->code = ov5640_formats[code->index].code;
342119a81c14SSteve Longerbeam 	return 0;
342219a81c14SSteve Longerbeam }
342319a81c14SSteve Longerbeam 
342419a81c14SSteve Longerbeam static int ov5640_s_stream(struct v4l2_subdev *sd, int enable)
342519a81c14SSteve Longerbeam {
342619a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
342719a81c14SSteve Longerbeam 	int ret = 0;
342819a81c14SSteve Longerbeam 
342919a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
343019a81c14SSteve Longerbeam 
343119a81c14SSteve Longerbeam 	if (sensor->streaming == !enable) {
343219a81c14SSteve Longerbeam 		if (enable && sensor->pending_mode_change) {
3433985cdcb0SHugues Fruchet 			ret = ov5640_set_mode(sensor);
343419a81c14SSteve Longerbeam 			if (ret)
343519a81c14SSteve Longerbeam 				goto out;
3436fb98e29fSHugues Fruchet 		}
3437e3ee691dSHugues Fruchet 
3438fb98e29fSHugues Fruchet 		if (enable && sensor->pending_fmt_change) {
3439e3ee691dSHugues Fruchet 			ret = ov5640_set_framefmt(sensor, &sensor->fmt);
3440e3ee691dSHugues Fruchet 			if (ret)
3441e3ee691dSHugues Fruchet 				goto out;
3442fb98e29fSHugues Fruchet 			sensor->pending_fmt_change = false;
344319a81c14SSteve Longerbeam 		}
344419a81c14SSteve Longerbeam 
34458e823f5cSJacopo Mondi 		if (ov5640_is_csi2(sensor))
3446f22996dbSHugues Fruchet 			ret = ov5640_set_stream_mipi(sensor, enable);
3447f22996dbSHugues Fruchet 		else
3448f22996dbSHugues Fruchet 			ret = ov5640_set_stream_dvp(sensor, enable);
3449f22996dbSHugues Fruchet 
345019a81c14SSteve Longerbeam 		if (!ret)
345119a81c14SSteve Longerbeam 			sensor->streaming = enable;
345219a81c14SSteve Longerbeam 	}
345319a81c14SSteve Longerbeam out:
345419a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
345519a81c14SSteve Longerbeam 	return ret;
345619a81c14SSteve Longerbeam }
345719a81c14SSteve Longerbeam 
345819a81c14SSteve Longerbeam static const struct v4l2_subdev_core_ops ov5640_core_ops = {
345919a81c14SSteve Longerbeam 	.s_power = ov5640_s_power,
34602d18fbc5SAkinobu Mita 	.log_status = v4l2_ctrl_subdev_log_status,
34612d18fbc5SAkinobu Mita 	.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
34622d18fbc5SAkinobu Mita 	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
346319a81c14SSteve Longerbeam };
346419a81c14SSteve Longerbeam 
346519a81c14SSteve Longerbeam static const struct v4l2_subdev_video_ops ov5640_video_ops = {
346619a81c14SSteve Longerbeam 	.g_frame_interval = ov5640_g_frame_interval,
346719a81c14SSteve Longerbeam 	.s_frame_interval = ov5640_s_frame_interval,
346819a81c14SSteve Longerbeam 	.s_stream = ov5640_s_stream,
346919a81c14SSteve Longerbeam };
347019a81c14SSteve Longerbeam 
347119a81c14SSteve Longerbeam static const struct v4l2_subdev_pad_ops ov5640_pad_ops = {
347219a81c14SSteve Longerbeam 	.enum_mbus_code = ov5640_enum_mbus_code,
347319a81c14SSteve Longerbeam 	.get_fmt = ov5640_get_fmt,
347419a81c14SSteve Longerbeam 	.set_fmt = ov5640_set_fmt,
347519a81c14SSteve Longerbeam 	.enum_frame_size = ov5640_enum_frame_size,
347619a81c14SSteve Longerbeam 	.enum_frame_interval = ov5640_enum_frame_interval,
347719a81c14SSteve Longerbeam };
347819a81c14SSteve Longerbeam 
347919a81c14SSteve Longerbeam static const struct v4l2_subdev_ops ov5640_subdev_ops = {
348019a81c14SSteve Longerbeam 	.core = &ov5640_core_ops,
348119a81c14SSteve Longerbeam 	.video = &ov5640_video_ops,
348219a81c14SSteve Longerbeam 	.pad = &ov5640_pad_ops,
348319a81c14SSteve Longerbeam };
348419a81c14SSteve Longerbeam 
348519a81c14SSteve Longerbeam static int ov5640_get_regulators(struct ov5640_dev *sensor)
348619a81c14SSteve Longerbeam {
348719a81c14SSteve Longerbeam 	int i;
348819a81c14SSteve Longerbeam 
348919a81c14SSteve Longerbeam 	for (i = 0; i < OV5640_NUM_SUPPLIES; i++)
349019a81c14SSteve Longerbeam 		sensor->supplies[i].supply = ov5640_supply_name[i];
349119a81c14SSteve Longerbeam 
349219a81c14SSteve Longerbeam 	return devm_regulator_bulk_get(&sensor->i2c_client->dev,
349319a81c14SSteve Longerbeam 				       OV5640_NUM_SUPPLIES,
349419a81c14SSteve Longerbeam 				       sensor->supplies);
349519a81c14SSteve Longerbeam }
349619a81c14SSteve Longerbeam 
34970f7acb52SHugues Fruchet static int ov5640_check_chip_id(struct ov5640_dev *sensor)
34980f7acb52SHugues Fruchet {
34990f7acb52SHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
35000f7acb52SHugues Fruchet 	int ret = 0;
35010f7acb52SHugues Fruchet 	u16 chip_id;
35020f7acb52SHugues Fruchet 
35030f7acb52SHugues Fruchet 	ret = ov5640_set_power_on(sensor);
35040f7acb52SHugues Fruchet 	if (ret)
35050f7acb52SHugues Fruchet 		return ret;
35060f7acb52SHugues Fruchet 
35070f7acb52SHugues Fruchet 	ret = ov5640_read_reg16(sensor, OV5640_REG_CHIP_ID, &chip_id);
35080f7acb52SHugues Fruchet 	if (ret) {
35090f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to read chip identifier\n",
35100f7acb52SHugues Fruchet 			__func__);
35110f7acb52SHugues Fruchet 		goto power_off;
35120f7acb52SHugues Fruchet 	}
35130f7acb52SHugues Fruchet 
35140f7acb52SHugues Fruchet 	if (chip_id != 0x5640) {
35150f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: wrong chip identifier, expected 0x5640, got 0x%x\n",
35160f7acb52SHugues Fruchet 			__func__, chip_id);
35170f7acb52SHugues Fruchet 		ret = -ENXIO;
35180f7acb52SHugues Fruchet 	}
35190f7acb52SHugues Fruchet 
35200f7acb52SHugues Fruchet power_off:
35210f7acb52SHugues Fruchet 	ov5640_set_power_off(sensor);
35220f7acb52SHugues Fruchet 	return ret;
35230f7acb52SHugues Fruchet }
35240f7acb52SHugues Fruchet 
3525e6714993SKieran Bingham static int ov5640_probe(struct i2c_client *client)
352619a81c14SSteve Longerbeam {
352719a81c14SSteve Longerbeam 	struct device *dev = &client->dev;
352819a81c14SSteve Longerbeam 	struct fwnode_handle *endpoint;
352919a81c14SSteve Longerbeam 	struct ov5640_dev *sensor;
3530e6441fdeSHugues Fruchet 	struct v4l2_mbus_framefmt *fmt;
3531c3f3ba3eSHugues Fruchet 	u32 rotation;
353219a81c14SSteve Longerbeam 	int ret;
353319a81c14SSteve Longerbeam 
353419a81c14SSteve Longerbeam 	sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
353519a81c14SSteve Longerbeam 	if (!sensor)
353619a81c14SSteve Longerbeam 		return -ENOMEM;
353719a81c14SSteve Longerbeam 
353819a81c14SSteve Longerbeam 	sensor->i2c_client = client;
3539fb98e29fSHugues Fruchet 
3540fb98e29fSHugues Fruchet 	/*
3541fb98e29fSHugues Fruchet 	 * default init sequence initialize sensor to
3542fb98e29fSHugues Fruchet 	 * YUV422 UYVY VGA@30fps
3543fb98e29fSHugues Fruchet 	 */
3544e6441fdeSHugues Fruchet 	fmt = &sensor->fmt;
3545fb98e29fSHugues Fruchet 	fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
3546fb98e29fSHugues Fruchet 	fmt->colorspace = V4L2_COLORSPACE_SRGB;
3547e6441fdeSHugues Fruchet 	fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
3548e6441fdeSHugues Fruchet 	fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
3549e6441fdeSHugues Fruchet 	fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
3550e6441fdeSHugues Fruchet 	fmt->width = 640;
3551e6441fdeSHugues Fruchet 	fmt->height = 480;
3552e6441fdeSHugues Fruchet 	fmt->field = V4L2_FIELD_NONE;
355319a81c14SSteve Longerbeam 	sensor->frame_interval.numerator = 1;
355419a81c14SSteve Longerbeam 	sensor->frame_interval.denominator = ov5640_framerates[OV5640_30_FPS];
355519a81c14SSteve Longerbeam 	sensor->current_fr = OV5640_30_FPS;
355619a81c14SSteve Longerbeam 	sensor->current_mode =
3557086c25f8SMaxime Ripard 		&ov5640_mode_data[OV5640_MODE_VGA_640_480];
3558985cdcb0SHugues Fruchet 	sensor->last_mode = sensor->current_mode;
35593c28588fSJacopo Mondi 	sensor->current_link_freq = OV5640_DEFAULT_LINK_FREQ;
356019a81c14SSteve Longerbeam 
356119a81c14SSteve Longerbeam 	sensor->ae_target = 52;
356219a81c14SSteve Longerbeam 
3563c3f3ba3eSHugues Fruchet 	/* optional indication of physical rotation of sensor */
3564c3f3ba3eSHugues Fruchet 	ret = fwnode_property_read_u32(dev_fwnode(&client->dev), "rotation",
3565c3f3ba3eSHugues Fruchet 				       &rotation);
3566c3f3ba3eSHugues Fruchet 	if (!ret) {
3567c3f3ba3eSHugues Fruchet 		switch (rotation) {
3568c3f3ba3eSHugues Fruchet 		case 180:
3569c3f3ba3eSHugues Fruchet 			sensor->upside_down = true;
35701771e9fbSGustavo A. R. Silva 			fallthrough;
3571c3f3ba3eSHugues Fruchet 		case 0:
3572c3f3ba3eSHugues Fruchet 			break;
3573c3f3ba3eSHugues Fruchet 		default:
3574c3f3ba3eSHugues Fruchet 			dev_warn(dev, "%u degrees rotation is not supported, ignoring...\n",
3575c3f3ba3eSHugues Fruchet 				 rotation);
3576c3f3ba3eSHugues Fruchet 		}
3577c3f3ba3eSHugues Fruchet 	}
3578c3f3ba3eSHugues Fruchet 
3579ce96bcf5SSakari Ailus 	endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev),
3580ce96bcf5SSakari Ailus 						  NULL);
358119a81c14SSteve Longerbeam 	if (!endpoint) {
358219a81c14SSteve Longerbeam 		dev_err(dev, "endpoint node not found\n");
358319a81c14SSteve Longerbeam 		return -EINVAL;
358419a81c14SSteve Longerbeam 	}
358519a81c14SSteve Longerbeam 
358619a81c14SSteve Longerbeam 	ret = v4l2_fwnode_endpoint_parse(endpoint, &sensor->ep);
358719a81c14SSteve Longerbeam 	fwnode_handle_put(endpoint);
358819a81c14SSteve Longerbeam 	if (ret) {
358919a81c14SSteve Longerbeam 		dev_err(dev, "Could not parse endpoint\n");
359019a81c14SSteve Longerbeam 		return ret;
359119a81c14SSteve Longerbeam 	}
359219a81c14SSteve Longerbeam 
35932c61e48dSLad Prabhakar 	if (sensor->ep.bus_type != V4L2_MBUS_PARALLEL &&
35942c61e48dSLad Prabhakar 	    sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY &&
35952c61e48dSLad Prabhakar 	    sensor->ep.bus_type != V4L2_MBUS_BT656) {
35962c61e48dSLad Prabhakar 		dev_err(dev, "Unsupported bus type %d\n", sensor->ep.bus_type);
35972c61e48dSLad Prabhakar 		return -EINVAL;
35982c61e48dSLad Prabhakar 	}
35992c61e48dSLad Prabhakar 
360019a81c14SSteve Longerbeam 	/* get system clock (xclk) */
360119a81c14SSteve Longerbeam 	sensor->xclk = devm_clk_get(dev, "xclk");
360219a81c14SSteve Longerbeam 	if (IS_ERR(sensor->xclk)) {
360319a81c14SSteve Longerbeam 		dev_err(dev, "failed to get xclk\n");
360419a81c14SSteve Longerbeam 		return PTR_ERR(sensor->xclk);
360519a81c14SSteve Longerbeam 	}
360619a81c14SSteve Longerbeam 
360719a81c14SSteve Longerbeam 	sensor->xclk_freq = clk_get_rate(sensor->xclk);
360819a81c14SSteve Longerbeam 	if (sensor->xclk_freq < OV5640_XCLK_MIN ||
360919a81c14SSteve Longerbeam 	    sensor->xclk_freq > OV5640_XCLK_MAX) {
361019a81c14SSteve Longerbeam 		dev_err(dev, "xclk frequency out of range: %d Hz\n",
361119a81c14SSteve Longerbeam 			sensor->xclk_freq);
361219a81c14SSteve Longerbeam 		return -EINVAL;
361319a81c14SSteve Longerbeam 	}
361419a81c14SSteve Longerbeam 
361519a81c14SSteve Longerbeam 	/* request optional power down pin */
361619a81c14SSteve Longerbeam 	sensor->pwdn_gpio = devm_gpiod_get_optional(dev, "powerdown",
361719a81c14SSteve Longerbeam 						    GPIOD_OUT_HIGH);
36188791a102SFabio Estevam 	if (IS_ERR(sensor->pwdn_gpio))
36198791a102SFabio Estevam 		return PTR_ERR(sensor->pwdn_gpio);
36208791a102SFabio Estevam 
362119a81c14SSteve Longerbeam 	/* request optional reset pin */
362219a81c14SSteve Longerbeam 	sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset",
362319a81c14SSteve Longerbeam 						     GPIOD_OUT_HIGH);
36248791a102SFabio Estevam 	if (IS_ERR(sensor->reset_gpio))
36258791a102SFabio Estevam 		return PTR_ERR(sensor->reset_gpio);
362619a81c14SSteve Longerbeam 
362719a81c14SSteve Longerbeam 	v4l2_i2c_subdev_init(&sensor->sd, client, &ov5640_subdev_ops);
362819a81c14SSteve Longerbeam 
36292d18fbc5SAkinobu Mita 	sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
36302d18fbc5SAkinobu Mita 			    V4L2_SUBDEV_FL_HAS_EVENTS;
363119a81c14SSteve Longerbeam 	sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
363219a81c14SSteve Longerbeam 	sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
363319a81c14SSteve Longerbeam 	ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
363419a81c14SSteve Longerbeam 	if (ret)
363519a81c14SSteve Longerbeam 		return ret;
363619a81c14SSteve Longerbeam 
363719a81c14SSteve Longerbeam 	ret = ov5640_get_regulators(sensor);
363819a81c14SSteve Longerbeam 	if (ret)
363919a81c14SSteve Longerbeam 		return ret;
364019a81c14SSteve Longerbeam 
364119a81c14SSteve Longerbeam 	mutex_init(&sensor->lock);
364219a81c14SSteve Longerbeam 
36430f7acb52SHugues Fruchet 	ret = ov5640_check_chip_id(sensor);
36440f7acb52SHugues Fruchet 	if (ret)
36450f7acb52SHugues Fruchet 		goto entity_cleanup;
36460f7acb52SHugues Fruchet 
364719a81c14SSteve Longerbeam 	ret = ov5640_init_controls(sensor);
364819a81c14SSteve Longerbeam 	if (ret)
364919a81c14SSteve Longerbeam 		goto entity_cleanup;
365019a81c14SSteve Longerbeam 
365115786f7bSSakari Ailus 	ret = v4l2_async_register_subdev_sensor(&sensor->sd);
365219a81c14SSteve Longerbeam 	if (ret)
365319a81c14SSteve Longerbeam 		goto free_ctrls;
365419a81c14SSteve Longerbeam 
365519a81c14SSteve Longerbeam 	return 0;
365619a81c14SSteve Longerbeam 
365719a81c14SSteve Longerbeam free_ctrls:
365819a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
365919a81c14SSteve Longerbeam entity_cleanup:
366019a81c14SSteve Longerbeam 	media_entity_cleanup(&sensor->sd.entity);
3661bfcba38dSTomi Valkeinen 	mutex_destroy(&sensor->lock);
366219a81c14SSteve Longerbeam 	return ret;
366319a81c14SSteve Longerbeam }
366419a81c14SSteve Longerbeam 
366519a81c14SSteve Longerbeam static int ov5640_remove(struct i2c_client *client)
366619a81c14SSteve Longerbeam {
366719a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
366819a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
366919a81c14SSteve Longerbeam 
367019a81c14SSteve Longerbeam 	v4l2_async_unregister_subdev(&sensor->sd);
367119a81c14SSteve Longerbeam 	media_entity_cleanup(&sensor->sd.entity);
367219a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
3673bfcba38dSTomi Valkeinen 	mutex_destroy(&sensor->lock);
367419a81c14SSteve Longerbeam 
367519a81c14SSteve Longerbeam 	return 0;
367619a81c14SSteve Longerbeam }
367719a81c14SSteve Longerbeam 
367819a81c14SSteve Longerbeam static const struct i2c_device_id ov5640_id[] = {
367919a81c14SSteve Longerbeam 	{"ov5640", 0},
368019a81c14SSteve Longerbeam 	{},
368119a81c14SSteve Longerbeam };
368219a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(i2c, ov5640_id);
368319a81c14SSteve Longerbeam 
368419a81c14SSteve Longerbeam static const struct of_device_id ov5640_dt_ids[] = {
368519a81c14SSteve Longerbeam 	{ .compatible = "ovti,ov5640" },
368619a81c14SSteve Longerbeam 	{ /* sentinel */ }
368719a81c14SSteve Longerbeam };
368819a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(of, ov5640_dt_ids);
368919a81c14SSteve Longerbeam 
369019a81c14SSteve Longerbeam static struct i2c_driver ov5640_i2c_driver = {
369119a81c14SSteve Longerbeam 	.driver = {
369219a81c14SSteve Longerbeam 		.name  = "ov5640",
369319a81c14SSteve Longerbeam 		.of_match_table	= ov5640_dt_ids,
369419a81c14SSteve Longerbeam 	},
369519a81c14SSteve Longerbeam 	.id_table = ov5640_id,
3696e6714993SKieran Bingham 	.probe_new = ov5640_probe,
369719a81c14SSteve Longerbeam 	.remove   = ov5640_remove,
369819a81c14SSteve Longerbeam };
369919a81c14SSteve Longerbeam 
370019a81c14SSteve Longerbeam module_i2c_driver(ov5640_i2c_driver);
370119a81c14SSteve Longerbeam 
370219a81c14SSteve Longerbeam MODULE_DESCRIPTION("OV5640 MIPI Camera Subdev Driver");
370319a81c14SSteve Longerbeam MODULE_LICENSE("GPL");
3704