xref: /openbmc/linux/drivers/media/i2c/ov5640.c (revision 0a43fcd7)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
219a81c14SSteve Longerbeam /*
319a81c14SSteve Longerbeam  * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
419a81c14SSteve Longerbeam  * Copyright (C) 2014-2017 Mentor Graphics Inc.
519a81c14SSteve Longerbeam  */
619a81c14SSteve Longerbeam 
719a81c14SSteve Longerbeam #include <linux/clk.h>
819a81c14SSteve Longerbeam #include <linux/clk-provider.h>
919a81c14SSteve Longerbeam #include <linux/clkdev.h>
1019a81c14SSteve Longerbeam #include <linux/ctype.h>
1119a81c14SSteve Longerbeam #include <linux/delay.h>
1219a81c14SSteve Longerbeam #include <linux/device.h>
1341d8d7f5SHugues Fruchet #include <linux/gpio/consumer.h>
1419a81c14SSteve Longerbeam #include <linux/i2c.h>
1519a81c14SSteve Longerbeam #include <linux/init.h>
1619a81c14SSteve Longerbeam #include <linux/module.h>
1719a81c14SSteve Longerbeam #include <linux/of_device.h>
1841d8d7f5SHugues Fruchet #include <linux/regulator/consumer.h>
1919a81c14SSteve Longerbeam #include <linux/slab.h>
2019a81c14SSteve Longerbeam #include <linux/types.h>
2119a81c14SSteve Longerbeam #include <media/v4l2-async.h>
2219a81c14SSteve Longerbeam #include <media/v4l2-ctrls.h>
2319a81c14SSteve Longerbeam #include <media/v4l2-device.h>
242d18fbc5SAkinobu Mita #include <media/v4l2-event.h>
2519a81c14SSteve Longerbeam #include <media/v4l2-fwnode.h>
2619a81c14SSteve Longerbeam #include <media/v4l2-subdev.h>
2719a81c14SSteve Longerbeam 
2819a81c14SSteve Longerbeam /* min/typical/max system clock (xclk) frequencies */
2919a81c14SSteve Longerbeam #define OV5640_XCLK_MIN  6000000
3041cb1c73SPhilipp Puschmann #define OV5640_XCLK_MAX 54000000
3119a81c14SSteve Longerbeam 
325113d5b3SJacopo Mondi #define OV5640_NATIVE_WIDTH		2624
335113d5b3SJacopo Mondi #define OV5640_NATIVE_HEIGHT		1964
345113d5b3SJacopo Mondi #define OV5640_PIXEL_ARRAY_TOP		14
355113d5b3SJacopo Mondi #define OV5640_PIXEL_ARRAY_LEFT		16
365113d5b3SJacopo Mondi #define OV5640_PIXEL_ARRAY_WIDTH	2592
375113d5b3SJacopo Mondi #define OV5640_PIXEL_ARRAY_HEIGHT	1944
385113d5b3SJacopo Mondi 
39bce93b82SJacopo Mondi /* FIXME: not documented. */
40bce93b82SJacopo Mondi #define OV5640_MIN_VBLANK	24
41bce93b82SJacopo Mondi #define OV5640_MAX_VTS		3375
42bce93b82SJacopo Mondi 
4319a81c14SSteve Longerbeam #define OV5640_DEFAULT_SLAVE_ID 0x3c
4419a81c14SSteve Longerbeam 
453c28588fSJacopo Mondi #define OV5640_LINK_RATE_MAX		490000000U
463c28588fSJacopo Mondi 
47d47c4126SHugues Fruchet #define OV5640_REG_SYS_RESET02		0x3002
48d47c4126SHugues Fruchet #define OV5640_REG_SYS_CLOCK_ENABLE02	0x3006
49f22996dbSHugues Fruchet #define OV5640_REG_SYS_CTRL0		0x3008
503b987d70SLad Prabhakar #define OV5640_REG_SYS_CTRL0_SW_PWDN	0x42
513b987d70SLad Prabhakar #define OV5640_REG_SYS_CTRL0_SW_PWUP	0x02
5219a81c14SSteve Longerbeam #define OV5640_REG_CHIP_ID		0x300a
53f22996dbSHugues Fruchet #define OV5640_REG_IO_MIPI_CTRL00	0x300e
54f22996dbSHugues Fruchet #define OV5640_REG_PAD_OUTPUT_ENABLE01	0x3017
55f22996dbSHugues Fruchet #define OV5640_REG_PAD_OUTPUT_ENABLE02	0x3018
5619a81c14SSteve Longerbeam #define OV5640_REG_PAD_OUTPUT00		0x3019
57f22996dbSHugues Fruchet #define OV5640_REG_SYSTEM_CONTROL1	0x302e
5819a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL0		0x3034
5919a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL1		0x3035
6019a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL2		0x3036
6119a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL3		0x3037
6219a81c14SSteve Longerbeam #define OV5640_REG_SLAVE_ID		0x3100
63f22996dbSHugues Fruchet #define OV5640_REG_SCCB_SYS_CTRL1	0x3103
6419a81c14SSteve Longerbeam #define OV5640_REG_SYS_ROOT_DIVIDER	0x3108
6519a81c14SSteve Longerbeam #define OV5640_REG_AWB_R_GAIN		0x3400
6619a81c14SSteve Longerbeam #define OV5640_REG_AWB_G_GAIN		0x3402
6719a81c14SSteve Longerbeam #define OV5640_REG_AWB_B_GAIN		0x3404
6819a81c14SSteve Longerbeam #define OV5640_REG_AWB_MANUAL_CTRL	0x3406
6919a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_HI	0x3500
7019a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_MED	0x3501
7119a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_LO	0x3502
7219a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_MANUAL	0x3503
7319a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_REAL_GAIN	0x350a
7419a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_VTS		0x350c
753145efcdSJacopo Mondi #define OV5640_REG_TIMING_HS		0x3800
763145efcdSJacopo Mondi #define OV5640_REG_TIMING_VS		0x3802
773145efcdSJacopo Mondi #define OV5640_REG_TIMING_HW		0x3804
783145efcdSJacopo Mondi #define OV5640_REG_TIMING_VH		0x3806
7986633417SMaxime Ripard #define OV5640_REG_TIMING_DVPHO		0x3808
8086633417SMaxime Ripard #define OV5640_REG_TIMING_DVPVO		0x380a
8119a81c14SSteve Longerbeam #define OV5640_REG_TIMING_HTS		0x380c
8219a81c14SSteve Longerbeam #define OV5640_REG_TIMING_VTS		0x380e
833145efcdSJacopo Mondi #define OV5640_REG_TIMING_HOFFS		0x3810
843145efcdSJacopo Mondi #define OV5640_REG_TIMING_VOFFS		0x3812
85ce85705aSHugues Fruchet #define OV5640_REG_TIMING_TC_REG20	0x3820
8619a81c14SSteve Longerbeam #define OV5640_REG_TIMING_TC_REG21	0x3821
8719a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL00		0x3a00
8819a81c14SSteve Longerbeam #define OV5640_REG_AEC_B50_STEP		0x3a08
8919a81c14SSteve Longerbeam #define OV5640_REG_AEC_B60_STEP		0x3a0a
9019a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0D		0x3a0d
9119a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0E		0x3a0e
9219a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0F		0x3a0f
9319a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL10		0x3a10
9419a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL11		0x3a11
9519a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1B		0x3a1b
9619a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1E		0x3a1e
9719a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1F		0x3a1f
9819a81c14SSteve Longerbeam #define OV5640_REG_HZ5060_CTRL00	0x3c00
9919a81c14SSteve Longerbeam #define OV5640_REG_HZ5060_CTRL01	0x3c01
10019a81c14SSteve Longerbeam #define OV5640_REG_SIGMADELTA_CTRL0C	0x3c0c
10119a81c14SSteve Longerbeam #define OV5640_REG_FRAME_CTRL01		0x4202
102e3ee691dSHugues Fruchet #define OV5640_REG_FORMAT_CONTROL00	0x4300
1037cb013b1SChen-Yu Tsai #define OV5640_REG_VFIFO_HSIZE		0x4602
1047cb013b1SChen-Yu Tsai #define OV5640_REG_VFIFO_VSIZE		0x4604
1052b5c18f9SChen-Yu Tsai #define OV5640_REG_JPG_MODE_SELECT	0x4713
1064039b037SLad Prabhakar #define OV5640_REG_CCIR656_CTRL00	0x4730
107f22996dbSHugues Fruchet #define OV5640_REG_POLARITY_CTRL00	0x4740
10819a81c14SSteve Longerbeam #define OV5640_REG_MIPI_CTRL00		0x4800
10919a81c14SSteve Longerbeam #define OV5640_REG_DEBUG_MODE		0x4814
1106c957ed7SJacopo Mondi #define OV5640_REG_PCLK_PERIOD		0x4837
111e3ee691dSHugues Fruchet #define OV5640_REG_ISP_FORMAT_MUX_CTRL	0x501f
11219a81c14SSteve Longerbeam #define OV5640_REG_PRE_ISP_TEST_SET1	0x503d
11319a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL0		0x5580
11419a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL1		0x5581
11519a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL3		0x5583
11619a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL4		0x5584
11719a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL5		0x5585
11819a81c14SSteve Longerbeam #define OV5640_REG_AVG_READOUT		0x56a1
11919a81c14SSteve Longerbeam 
12019a81c14SSteve Longerbeam enum ov5640_mode_id {
12132ea5e05SHugues Fruchet 	OV5640_MODE_QQVGA_160_120 = 0,
12232ea5e05SHugues Fruchet 	OV5640_MODE_QCIF_176_144,
12319a81c14SSteve Longerbeam 	OV5640_MODE_QVGA_320_240,
12419a81c14SSteve Longerbeam 	OV5640_MODE_VGA_640_480,
12519a81c14SSteve Longerbeam 	OV5640_MODE_NTSC_720_480,
12619a81c14SSteve Longerbeam 	OV5640_MODE_PAL_720_576,
12719a81c14SSteve Longerbeam 	OV5640_MODE_XGA_1024_768,
12819a81c14SSteve Longerbeam 	OV5640_MODE_720P_1280_720,
12919a81c14SSteve Longerbeam 	OV5640_MODE_1080P_1920_1080,
13019a81c14SSteve Longerbeam 	OV5640_MODE_QSXGA_2592_1944,
13119a81c14SSteve Longerbeam 	OV5640_NUM_MODES,
13219a81c14SSteve Longerbeam };
13319a81c14SSteve Longerbeam 
13419a81c14SSteve Longerbeam enum ov5640_frame_rate {
13519a81c14SSteve Longerbeam 	OV5640_15_FPS = 0,
13619a81c14SSteve Longerbeam 	OV5640_30_FPS,
137e823fb16SMaxime Ripard 	OV5640_60_FPS,
13819a81c14SSteve Longerbeam 	OV5640_NUM_FRAMERATES,
13919a81c14SSteve Longerbeam };
14019a81c14SSteve Longerbeam 
14122845bf2SJacopo Mondi enum ov5640_pixel_rate_id {
14222845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_168M,
14322845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_148M,
14422845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_124M,
14522845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_96M,
14622845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_48M,
14722845bf2SJacopo Mondi 	OV5640_NUM_PIXEL_RATES,
14822845bf2SJacopo Mondi };
14922845bf2SJacopo Mondi 
15022845bf2SJacopo Mondi /*
15122845bf2SJacopo Mondi  * The chip manual suggests 24/48/96/192 MHz pixel clocks.
15222845bf2SJacopo Mondi  *
15322845bf2SJacopo Mondi  * 192MHz exceeds the sysclk limits; use 168MHz as maximum pixel rate for
15422845bf2SJacopo Mondi  * full resolution mode @15 FPS.
15522845bf2SJacopo Mondi  */
15622845bf2SJacopo Mondi static const u32 ov5640_pixel_rates[] = {
15722845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_168M] = 168000000,
15822845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_148M] = 148000000,
15922845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_124M] = 124000000,
16022845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_96M] = 96000000,
16122845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_48M] = 48000000,
16222845bf2SJacopo Mondi };
16322845bf2SJacopo Mondi 
1647a3b8d4bSJacopo Mondi /*
1657a3b8d4bSJacopo Mondi  * MIPI CSI-2 link frequencies.
1667a3b8d4bSJacopo Mondi  *
1677a3b8d4bSJacopo Mondi  * Derived from the above defined pixel rate for bpp = (8, 16, 24) and
1687a3b8d4bSJacopo Mondi  * data_lanes = (1, 2)
1697a3b8d4bSJacopo Mondi  *
1707a3b8d4bSJacopo Mondi  * link_freq = (pixel_rate * bpp) / (2 * data_lanes)
1717a3b8d4bSJacopo Mondi  */
1727a3b8d4bSJacopo Mondi static const s64 ov5640_csi2_link_freqs[] = {
1737a3b8d4bSJacopo Mondi 	992000000, 888000000, 768000000, 744000000, 672000000, 672000000,
1747a3b8d4bSJacopo Mondi 	592000000, 592000000, 576000000, 576000000, 496000000, 496000000,
1757a3b8d4bSJacopo Mondi 	384000000, 384000000, 384000000, 336000000, 296000000, 288000000,
1767a3b8d4bSJacopo Mondi 	248000000, 192000000, 192000000, 192000000, 96000000,
1777a3b8d4bSJacopo Mondi };
1787a3b8d4bSJacopo Mondi 
1797a3b8d4bSJacopo Mondi /* Link freq for default mode: UYVY 16 bpp, 2 data lanes. */
1807a3b8d4bSJacopo Mondi #define OV5640_DEFAULT_LINK_FREQ	13
1817a3b8d4bSJacopo Mondi 
182b7ed3abdSLoic Poulain enum ov5640_format_mux {
183b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_YUV422 = 0,
184b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_RGB,
185b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_DITHER,
186b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_RAW_DPC,
187b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_SNR_RAW,
188b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_RAW_CIP,
189b7ed3abdSLoic Poulain };
190b7ed3abdSLoic Poulain 
1912d7671f6SJacopo Mondi static const struct ov5640_pixfmt {
192e3ee691dSHugues Fruchet 	u32 code;
193e3ee691dSHugues Fruchet 	u32 colorspace;
1942d7671f6SJacopo Mondi 	u8 bpp;
1952d7671f6SJacopo Mondi } ov5640_formats[] = {
1962d7671f6SJacopo Mondi 	{
1972d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_JPEG_1X8,
1982d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_JPEG,
1992d7671f6SJacopo Mondi 		.bpp = 16,
2002d7671f6SJacopo Mondi 	}, {
2012d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_UYVY8_2X8,
2022d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2032d7671f6SJacopo Mondi 		.bpp = 16,
2042d7671f6SJacopo Mondi 	}, {
2052d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_UYVY8_1X16,
2062d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2072d7671f6SJacopo Mondi 		.bpp = 16,
2082d7671f6SJacopo Mondi 	}, {
2092d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_YUYV8_2X8,
2102d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2112d7671f6SJacopo Mondi 		.bpp = 16,
2122d7671f6SJacopo Mondi 	}, {
2132d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_YUYV8_1X16,
2142d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2152d7671f6SJacopo Mondi 		.bpp = 16,
2162d7671f6SJacopo Mondi 	}, {
2172d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_RGB565_2X8_LE,
2182d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2192d7671f6SJacopo Mondi 		.bpp = 16,
2202d7671f6SJacopo Mondi 	}, {
2212d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_RGB565_2X8_BE,
2222d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2232d7671f6SJacopo Mondi 		.bpp = 16,
2242d7671f6SJacopo Mondi 	}, {
225*0a43fcd7SJacopo Mondi 		.code = MEDIA_BUS_FMT_RGB565_1X16,
226*0a43fcd7SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
227*0a43fcd7SJacopo Mondi 		.bpp = 16,
228*0a43fcd7SJacopo Mondi 	}, {
2292d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_SBGGR8_1X8,
2302d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2312d7671f6SJacopo Mondi 		.bpp = 8,
2322d7671f6SJacopo Mondi 	}, {
2332d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_SGBRG8_1X8,
2342d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2352d7671f6SJacopo Mondi 		.bpp = 8
2362d7671f6SJacopo Mondi 	}, {
2372d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_SGRBG8_1X8,
2382d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2392d7671f6SJacopo Mondi 		.bpp = 8,
2402d7671f6SJacopo Mondi 	}, {
2412d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_SRGGB8_1X8,
2422d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2432d7671f6SJacopo Mondi 		.bpp = 8,
2442d7671f6SJacopo Mondi 	},
245e3ee691dSHugues Fruchet };
246e3ee691dSHugues Fruchet 
2473c28588fSJacopo Mondi static u32 ov5640_code_to_bpp(u32 code)
2483c28588fSJacopo Mondi {
2493c28588fSJacopo Mondi 	unsigned int i;
2503c28588fSJacopo Mondi 
2513c28588fSJacopo Mondi 	for (i = 0; i < ARRAY_SIZE(ov5640_formats); ++i) {
2523c28588fSJacopo Mondi 		if (ov5640_formats[i].code == code)
2533c28588fSJacopo Mondi 			return ov5640_formats[i].bpp;
2543c28588fSJacopo Mondi 	}
2553c28588fSJacopo Mondi 
2563c28588fSJacopo Mondi 	return 0;
2573c28588fSJacopo Mondi }
2583c28588fSJacopo Mondi 
25919a81c14SSteve Longerbeam /*
26019a81c14SSteve Longerbeam  * FIXME: remove this when a subdev API becomes available
26119a81c14SSteve Longerbeam  * to set the MIPI CSI-2 virtual channel.
26219a81c14SSteve Longerbeam  */
26319a81c14SSteve Longerbeam static unsigned int virtual_channel;
2648670d70aSHugues Fruchet module_param(virtual_channel, uint, 0444);
26519a81c14SSteve Longerbeam MODULE_PARM_DESC(virtual_channel,
26619a81c14SSteve Longerbeam 		 "MIPI CSI-2 virtual channel (0..3), default 0");
26719a81c14SSteve Longerbeam 
26819a81c14SSteve Longerbeam static const int ov5640_framerates[] = {
26919a81c14SSteve Longerbeam 	[OV5640_15_FPS] = 15,
27019a81c14SSteve Longerbeam 	[OV5640_30_FPS] = 30,
271e823fb16SMaxime Ripard 	[OV5640_60_FPS] = 60,
27219a81c14SSteve Longerbeam };
27319a81c14SSteve Longerbeam 
27419a81c14SSteve Longerbeam /* regulator supplies */
27519a81c14SSteve Longerbeam static const char * const ov5640_supply_name[] = {
27641d8d7f5SHugues Fruchet 	"DOVDD", /* Digital I/O (1.8V) supply */
27719a81c14SSteve Longerbeam 	"AVDD",  /* Analog (2.8V) supply */
27824c8ac89SFabio Estevam 	"DVDD",  /* Digital Core (1.5V) supply */
27919a81c14SSteve Longerbeam };
28019a81c14SSteve Longerbeam 
28119a81c14SSteve Longerbeam #define OV5640_NUM_SUPPLIES ARRAY_SIZE(ov5640_supply_name)
28219a81c14SSteve Longerbeam 
28319a81c14SSteve Longerbeam /*
28419a81c14SSteve Longerbeam  * Image size under 1280 * 960 are SUBSAMPLING
28519a81c14SSteve Longerbeam  * Image size upper 1280 * 960 are SCALING
28619a81c14SSteve Longerbeam  */
28719a81c14SSteve Longerbeam enum ov5640_downsize_mode {
28819a81c14SSteve Longerbeam 	SUBSAMPLING,
28919a81c14SSteve Longerbeam 	SCALING,
29019a81c14SSteve Longerbeam };
29119a81c14SSteve Longerbeam 
29219a81c14SSteve Longerbeam struct reg_value {
29319a81c14SSteve Longerbeam 	u16 reg_addr;
29419a81c14SSteve Longerbeam 	u8 val;
29519a81c14SSteve Longerbeam 	u8 mask;
29619a81c14SSteve Longerbeam 	u32 delay_ms;
29719a81c14SSteve Longerbeam };
29819a81c14SSteve Longerbeam 
2995113d5b3SJacopo Mondi struct ov5640_timings {
3003145efcdSJacopo Mondi 	/* Analog crop rectangle. */
3013145efcdSJacopo Mondi 	struct v4l2_rect analog_crop;
3023145efcdSJacopo Mondi 	/* Visibile crop: from analog crop top-left corner. */
3033145efcdSJacopo Mondi 	struct v4l2_rect crop;
3045113d5b3SJacopo Mondi 	/* Total pixels per line: width + fixed hblank. */
305476dec01SMaxime Ripard 	u32 htot;
3065113d5b3SJacopo Mondi 	/* Default vertical blanking: frame height = height + vblank. */
3073145efcdSJacopo Mondi 	u32 vblank_def;
3085113d5b3SJacopo Mondi };
3095113d5b3SJacopo Mondi 
3105113d5b3SJacopo Mondi struct ov5640_mode_info {
3115113d5b3SJacopo Mondi 	enum ov5640_mode_id id;
3125113d5b3SJacopo Mondi 	enum ov5640_downsize_mode dn_mode;
3135113d5b3SJacopo Mondi 	enum ov5640_pixel_rate_id pixel_rate;
3145113d5b3SJacopo Mondi 
3155113d5b3SJacopo Mondi 	unsigned int width;
3165113d5b3SJacopo Mondi 	unsigned int height;
3175113d5b3SJacopo Mondi 
3185113d5b3SJacopo Mondi 	struct ov5640_timings dvp_timings;
3195113d5b3SJacopo Mondi 	struct ov5640_timings csi2_timings;
3205113d5b3SJacopo Mondi 
32119a81c14SSteve Longerbeam 	const struct reg_value *reg_data;
32219a81c14SSteve Longerbeam 	u32 reg_data_size;
3235113d5b3SJacopo Mondi 
3245113d5b3SJacopo Mondi 	/* Used by s_frame_interval only. */
3255554c80eSAdam Ford 	u32 max_fps;
32619f2e3e6SHugues Fruchet 	u32 def_fps;
32719a81c14SSteve Longerbeam };
32819a81c14SSteve Longerbeam 
32919a81c14SSteve Longerbeam struct ov5640_ctrls {
33019a81c14SSteve Longerbeam 	struct v4l2_ctrl_handler handler;
331cc196e48SBenoit Parrot 	struct v4l2_ctrl *pixel_rate;
3327a3b8d4bSJacopo Mondi 	struct v4l2_ctrl *link_freq;
33332979f67SJacopo Mondi 	struct v4l2_ctrl *hblank;
334bce93b82SJacopo Mondi 	struct v4l2_ctrl *vblank;
33519a81c14SSteve Longerbeam 	struct {
33619a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_exp;
33719a81c14SSteve Longerbeam 		struct v4l2_ctrl *exposure;
33819a81c14SSteve Longerbeam 	};
33919a81c14SSteve Longerbeam 	struct {
34019a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_wb;
34119a81c14SSteve Longerbeam 		struct v4l2_ctrl *blue_balance;
34219a81c14SSteve Longerbeam 		struct v4l2_ctrl *red_balance;
34319a81c14SSteve Longerbeam 	};
34419a81c14SSteve Longerbeam 	struct {
34519a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_gain;
34619a81c14SSteve Longerbeam 		struct v4l2_ctrl *gain;
34719a81c14SSteve Longerbeam 	};
34819a81c14SSteve Longerbeam 	struct v4l2_ctrl *brightness;
3491068fecaSMylène Josserand 	struct v4l2_ctrl *light_freq;
35019a81c14SSteve Longerbeam 	struct v4l2_ctrl *saturation;
35119a81c14SSteve Longerbeam 	struct v4l2_ctrl *contrast;
35219a81c14SSteve Longerbeam 	struct v4l2_ctrl *hue;
35319a81c14SSteve Longerbeam 	struct v4l2_ctrl *test_pattern;
354ce85705aSHugues Fruchet 	struct v4l2_ctrl *hflip;
355ce85705aSHugues Fruchet 	struct v4l2_ctrl *vflip;
35619a81c14SSteve Longerbeam };
35719a81c14SSteve Longerbeam 
35819a81c14SSteve Longerbeam struct ov5640_dev {
35919a81c14SSteve Longerbeam 	struct i2c_client *i2c_client;
36019a81c14SSteve Longerbeam 	struct v4l2_subdev sd;
36119a81c14SSteve Longerbeam 	struct media_pad pad;
36219a81c14SSteve Longerbeam 	struct v4l2_fwnode_endpoint ep; /* the parsed DT endpoint info */
36319a81c14SSteve Longerbeam 	struct clk *xclk; /* system clock to OV5640 */
36419a81c14SSteve Longerbeam 	u32 xclk_freq;
36519a81c14SSteve Longerbeam 
36619a81c14SSteve Longerbeam 	struct regulator_bulk_data supplies[OV5640_NUM_SUPPLIES];
36719a81c14SSteve Longerbeam 	struct gpio_desc *reset_gpio;
36819a81c14SSteve Longerbeam 	struct gpio_desc *pwdn_gpio;
369c3f3ba3eSHugues Fruchet 	bool   upside_down;
37019a81c14SSteve Longerbeam 
37119a81c14SSteve Longerbeam 	/* lock to protect all members below */
37219a81c14SSteve Longerbeam 	struct mutex lock;
37319a81c14SSteve Longerbeam 
37419a81c14SSteve Longerbeam 	int power_count;
37519a81c14SSteve Longerbeam 
37619a81c14SSteve Longerbeam 	struct v4l2_mbus_framefmt fmt;
377fb98e29fSHugues Fruchet 	bool pending_fmt_change;
37819a81c14SSteve Longerbeam 
37919a81c14SSteve Longerbeam 	const struct ov5640_mode_info *current_mode;
380985cdcb0SHugues Fruchet 	const struct ov5640_mode_info *last_mode;
38119a81c14SSteve Longerbeam 	enum ov5640_frame_rate current_fr;
38219a81c14SSteve Longerbeam 	struct v4l2_fract frame_interval;
3833c28588fSJacopo Mondi 	s64 current_link_freq;
38419a81c14SSteve Longerbeam 
38519a81c14SSteve Longerbeam 	struct ov5640_ctrls ctrls;
38619a81c14SSteve Longerbeam 
38719a81c14SSteve Longerbeam 	u32 prev_sysclk, prev_hts;
38819a81c14SSteve Longerbeam 	u32 ae_low, ae_high, ae_target;
38919a81c14SSteve Longerbeam 
39019a81c14SSteve Longerbeam 	bool pending_mode_change;
39119a81c14SSteve Longerbeam 	bool streaming;
39219a81c14SSteve Longerbeam };
39319a81c14SSteve Longerbeam 
39419a81c14SSteve Longerbeam static inline struct ov5640_dev *to_ov5640_dev(struct v4l2_subdev *sd)
39519a81c14SSteve Longerbeam {
39619a81c14SSteve Longerbeam 	return container_of(sd, struct ov5640_dev, sd);
39719a81c14SSteve Longerbeam }
39819a81c14SSteve Longerbeam 
39919a81c14SSteve Longerbeam static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
40019a81c14SSteve Longerbeam {
40119a81c14SSteve Longerbeam 	return &container_of(ctrl->handler, struct ov5640_dev,
40219a81c14SSteve Longerbeam 			     ctrls.handler)->sd;
40319a81c14SSteve Longerbeam }
40419a81c14SSteve Longerbeam 
4058e823f5cSJacopo Mondi static inline bool ov5640_is_csi2(const struct ov5640_dev *sensor)
4068e823f5cSJacopo Mondi {
4078e823f5cSJacopo Mondi 	return sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY;
4088e823f5cSJacopo Mondi }
4098e823f5cSJacopo Mondi 
41019a81c14SSteve Longerbeam /*
41119a81c14SSteve Longerbeam  * FIXME: all of these register tables are likely filled with
41219a81c14SSteve Longerbeam  * entries that set the register to their power-on default values,
41319a81c14SSteve Longerbeam  * and which are otherwise not touched by this driver. Those entries
41419a81c14SSteve Longerbeam  * should be identified and removed to speed register load time
41519a81c14SSteve Longerbeam  * over i2c.
41619a81c14SSteve Longerbeam  */
417fb98e29fSHugues Fruchet /* YUV422 UYVY VGA@30fps */
41890b0f355SJacopo Mondi 
41990b0f355SJacopo Mondi static const struct v4l2_mbus_framefmt ov5640_default_fmt = {
42090b0f355SJacopo Mondi 	.code = MEDIA_BUS_FMT_UYVY8_2X8,
42190b0f355SJacopo Mondi 	.width = 640,
42290b0f355SJacopo Mondi 	.height = 480,
42390b0f355SJacopo Mondi 	.colorspace = V4L2_COLORSPACE_SRGB,
42490b0f355SJacopo Mondi 	.ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SRGB),
42590b0f355SJacopo Mondi 	.quantization = V4L2_QUANTIZATION_FULL_RANGE,
42690b0f355SJacopo Mondi 	.xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SRGB),
42790b0f355SJacopo Mondi 	.field = V4L2_FIELD_NONE,
42890b0f355SJacopo Mondi };
42990b0f355SJacopo Mondi 
430e4359019SJacopo Mondi static const struct reg_value ov5640_init_setting[] = {
43119a81c14SSteve Longerbeam 	{0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0},
432576f5d4bSLad Prabhakar 	{0x3103, 0x03, 0, 0}, {0x3630, 0x36, 0, 0},
43319a81c14SSteve Longerbeam 	{0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0},
43419a81c14SSteve Longerbeam 	{0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0},
43519a81c14SSteve Longerbeam 	{0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0},
43619a81c14SSteve Longerbeam 	{0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, {0x3906, 0x10, 0, 0},
43719a81c14SSteve Longerbeam 	{0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, {0x3600, 0x08, 0, 0},
43819a81c14SSteve Longerbeam 	{0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, {0x3620, 0x52, 0, 0},
43919a81c14SSteve Longerbeam 	{0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, {0x3a13, 0x43, 0, 0},
44019a81c14SSteve Longerbeam 	{0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3635, 0x13, 0, 0},
44119a81c14SSteve Longerbeam 	{0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, {0x3622, 0x01, 0, 0},
44219a81c14SSteve Longerbeam 	{0x3c01, 0xa4, 0, 0}, {0x3c04, 0x28, 0, 0}, {0x3c05, 0x98, 0, 0},
44319a81c14SSteve Longerbeam 	{0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0},
44419a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
44519a81c14SSteve Longerbeam 	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
4463145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
44719a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
44819a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
44919a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
45019a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
45119a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
45219a81c14SSteve Longerbeam 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0},
45319a81c14SSteve Longerbeam 	{0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0},
454aa4bb8b8SJacopo Mondi 	{0x302e, 0x08, 0, 0}, {0x4300, 0x3f, 0, 0},
4552b5c18f9SChen-Yu Tsai 	{0x501f, 0x00, 0, 0}, {0x4407, 0x04, 0, 0},
45619a81c14SSteve Longerbeam 	{0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
457aa4bb8b8SJacopo Mondi 	{0x4837, 0x0a, 0, 0}, {0x3824, 0x02, 0, 0},
45819a81c14SSteve Longerbeam 	{0x5000, 0xa7, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0},
45919a81c14SSteve Longerbeam 	{0x5181, 0xf2, 0, 0}, {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0},
46019a81c14SSteve Longerbeam 	{0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0},
46119a81c14SSteve Longerbeam 	{0x5187, 0x09, 0, 0}, {0x5188, 0x09, 0, 0}, {0x5189, 0x88, 0, 0},
46219a81c14SSteve Longerbeam 	{0x518a, 0x54, 0, 0}, {0x518b, 0xee, 0, 0}, {0x518c, 0xb2, 0, 0},
46319a81c14SSteve Longerbeam 	{0x518d, 0x50, 0, 0}, {0x518e, 0x34, 0, 0}, {0x518f, 0x6b, 0, 0},
46419a81c14SSteve Longerbeam 	{0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0},
46519a81c14SSteve Longerbeam 	{0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0},
46619a81c14SSteve Longerbeam 	{0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0},
46719a81c14SSteve Longerbeam 	{0x5199, 0x6c, 0, 0}, {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0},
46819a81c14SSteve Longerbeam 	{0x519c, 0x09, 0, 0}, {0x519d, 0x2b, 0, 0}, {0x519e, 0x38, 0, 0},
46919a81c14SSteve Longerbeam 	{0x5381, 0x1e, 0, 0}, {0x5382, 0x5b, 0, 0}, {0x5383, 0x08, 0, 0},
47019a81c14SSteve Longerbeam 	{0x5384, 0x0a, 0, 0}, {0x5385, 0x7e, 0, 0}, {0x5386, 0x88, 0, 0},
47119a81c14SSteve Longerbeam 	{0x5387, 0x7c, 0, 0}, {0x5388, 0x6c, 0, 0}, {0x5389, 0x10, 0, 0},
47219a81c14SSteve Longerbeam 	{0x538a, 0x01, 0, 0}, {0x538b, 0x98, 0, 0}, {0x5300, 0x08, 0, 0},
47319a81c14SSteve Longerbeam 	{0x5301, 0x30, 0, 0}, {0x5302, 0x10, 0, 0}, {0x5303, 0x00, 0, 0},
47419a81c14SSteve Longerbeam 	{0x5304, 0x08, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x08, 0, 0},
47519a81c14SSteve Longerbeam 	{0x5307, 0x16, 0, 0}, {0x5309, 0x08, 0, 0}, {0x530a, 0x30, 0, 0},
47619a81c14SSteve Longerbeam 	{0x530b, 0x04, 0, 0}, {0x530c, 0x06, 0, 0}, {0x5480, 0x01, 0, 0},
47719a81c14SSteve Longerbeam 	{0x5481, 0x08, 0, 0}, {0x5482, 0x14, 0, 0}, {0x5483, 0x28, 0, 0},
47819a81c14SSteve Longerbeam 	{0x5484, 0x51, 0, 0}, {0x5485, 0x65, 0, 0}, {0x5486, 0x71, 0, 0},
47919a81c14SSteve Longerbeam 	{0x5487, 0x7d, 0, 0}, {0x5488, 0x87, 0, 0}, {0x5489, 0x91, 0, 0},
48019a81c14SSteve Longerbeam 	{0x548a, 0x9a, 0, 0}, {0x548b, 0xaa, 0, 0}, {0x548c, 0xb8, 0, 0},
48119a81c14SSteve Longerbeam 	{0x548d, 0xcd, 0, 0}, {0x548e, 0xdd, 0, 0}, {0x548f, 0xea, 0, 0},
48219a81c14SSteve Longerbeam 	{0x5490, 0x1d, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5583, 0x40, 0, 0},
48319a81c14SSteve Longerbeam 	{0x5584, 0x10, 0, 0}, {0x5589, 0x10, 0, 0}, {0x558a, 0x00, 0, 0},
48419a81c14SSteve Longerbeam 	{0x558b, 0xf8, 0, 0}, {0x5800, 0x23, 0, 0}, {0x5801, 0x14, 0, 0},
48519a81c14SSteve Longerbeam 	{0x5802, 0x0f, 0, 0}, {0x5803, 0x0f, 0, 0}, {0x5804, 0x12, 0, 0},
48619a81c14SSteve Longerbeam 	{0x5805, 0x26, 0, 0}, {0x5806, 0x0c, 0, 0}, {0x5807, 0x08, 0, 0},
48719a81c14SSteve Longerbeam 	{0x5808, 0x05, 0, 0}, {0x5809, 0x05, 0, 0}, {0x580a, 0x08, 0, 0},
48819a81c14SSteve Longerbeam 	{0x580b, 0x0d, 0, 0}, {0x580c, 0x08, 0, 0}, {0x580d, 0x03, 0, 0},
48919a81c14SSteve Longerbeam 	{0x580e, 0x00, 0, 0}, {0x580f, 0x00, 0, 0}, {0x5810, 0x03, 0, 0},
49019a81c14SSteve Longerbeam 	{0x5811, 0x09, 0, 0}, {0x5812, 0x07, 0, 0}, {0x5813, 0x03, 0, 0},
49119a81c14SSteve Longerbeam 	{0x5814, 0x00, 0, 0}, {0x5815, 0x01, 0, 0}, {0x5816, 0x03, 0, 0},
49219a81c14SSteve Longerbeam 	{0x5817, 0x08, 0, 0}, {0x5818, 0x0d, 0, 0}, {0x5819, 0x08, 0, 0},
49319a81c14SSteve Longerbeam 	{0x581a, 0x05, 0, 0}, {0x581b, 0x06, 0, 0}, {0x581c, 0x08, 0, 0},
49419a81c14SSteve Longerbeam 	{0x581d, 0x0e, 0, 0}, {0x581e, 0x29, 0, 0}, {0x581f, 0x17, 0, 0},
49519a81c14SSteve Longerbeam 	{0x5820, 0x11, 0, 0}, {0x5821, 0x11, 0, 0}, {0x5822, 0x15, 0, 0},
49619a81c14SSteve Longerbeam 	{0x5823, 0x28, 0, 0}, {0x5824, 0x46, 0, 0}, {0x5825, 0x26, 0, 0},
49719a81c14SSteve Longerbeam 	{0x5826, 0x08, 0, 0}, {0x5827, 0x26, 0, 0}, {0x5828, 0x64, 0, 0},
49819a81c14SSteve Longerbeam 	{0x5829, 0x26, 0, 0}, {0x582a, 0x24, 0, 0}, {0x582b, 0x22, 0, 0},
49919a81c14SSteve Longerbeam 	{0x582c, 0x24, 0, 0}, {0x582d, 0x24, 0, 0}, {0x582e, 0x06, 0, 0},
50019a81c14SSteve Longerbeam 	{0x582f, 0x22, 0, 0}, {0x5830, 0x40, 0, 0}, {0x5831, 0x42, 0, 0},
50119a81c14SSteve Longerbeam 	{0x5832, 0x24, 0, 0}, {0x5833, 0x26, 0, 0}, {0x5834, 0x24, 0, 0},
50219a81c14SSteve Longerbeam 	{0x5835, 0x22, 0, 0}, {0x5836, 0x22, 0, 0}, {0x5837, 0x26, 0, 0},
50319a81c14SSteve Longerbeam 	{0x5838, 0x44, 0, 0}, {0x5839, 0x24, 0, 0}, {0x583a, 0x26, 0, 0},
50419a81c14SSteve Longerbeam 	{0x583b, 0x28, 0, 0}, {0x583c, 0x42, 0, 0}, {0x583d, 0xce, 0, 0},
50519a81c14SSteve Longerbeam 	{0x5025, 0x00, 0, 0}, {0x3a0f, 0x30, 0, 0}, {0x3a10, 0x28, 0, 0},
50619a81c14SSteve Longerbeam 	{0x3a1b, 0x30, 0, 0}, {0x3a1e, 0x26, 0, 0}, {0x3a11, 0x60, 0, 0},
50719a81c14SSteve Longerbeam 	{0x3a1f, 0x14, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3c00, 0x04, 0, 300},
50819a81c14SSteve Longerbeam };
50919a81c14SSteve Longerbeam 
510db15c195SJacopo Mondi static const struct reg_value ov5640_setting_low_res[] = {
511c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
51219a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
513ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
5143145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
51519a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
51619a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
51719a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
51819a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
51919a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5202b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
521e15197bdSJacopo Mondi 	{0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0},
52219a81c14SSteve Longerbeam };
52319a81c14SSteve Longerbeam 
524086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_720P_1280_720[] = {
525c14d107eSMaxime Ripard 	{0x3c07, 0x07, 0, 0},
52619a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
527ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
5283145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
52919a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
53019a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0},
53119a81c14SSteve Longerbeam 	{0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0},
53219a81c14SSteve Longerbeam 	{0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0},
53319a81c14SSteve Longerbeam 	{0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0},
5342b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
53519a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
53619a81c14SSteve Longerbeam 	{0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0},
53719a81c14SSteve Longerbeam };
53819a81c14SSteve Longerbeam 
539086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_1080P_1920_1080[] = {
540c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
54119a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
542ce85705aSHugues Fruchet 	{0x3814, 0x11, 0, 0},
5433145efcdSJacopo Mondi 	{0x3815, 0x11, 0, 0},
54419a81c14SSteve Longerbeam 	{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
54519a81c14SSteve Longerbeam 	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
54619a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
54719a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
54819a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5492b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0},
55019a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
551c14d107eSMaxime Ripard 	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0},
552c14d107eSMaxime Ripard 	{0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0},
55319a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
554476dec01SMaxime Ripard 	{0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0},
55519a81c14SSteve Longerbeam 	{0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0},
55619a81c14SSteve Longerbeam 	{0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0},
55719a81c14SSteve Longerbeam 	{0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0},
5582b5c18f9SChen-Yu Tsai 	{0x3a15, 0x60, 0, 0}, {0x4407, 0x04, 0, 0},
55919a81c14SSteve Longerbeam 	{0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0},
56092b9096cSBenoit Parrot 	{0x4005, 0x1a, 0, 0},
56119a81c14SSteve Longerbeam };
56219a81c14SSteve Longerbeam 
563086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_QSXGA_2592_1944[] = {
564c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
56519a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
566ce85705aSHugues Fruchet 	{0x3814, 0x11, 0, 0},
5673145efcdSJacopo Mondi 	{0x3815, 0x11, 0, 0},
56819a81c14SSteve Longerbeam 	{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
56919a81c14SSteve Longerbeam 	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
57019a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
57119a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
57219a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5732b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0},
57419a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
57519a81c14SSteve Longerbeam 	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70},
57619a81c14SSteve Longerbeam };
57719a81c14SSteve Longerbeam 
5785113d5b3SJacopo Mondi static const struct ov5640_mode_info ov5640_mode_data[OV5640_NUM_MODES] = {
5798409d017SJacopo Mondi 	{
5808409d017SJacopo Mondi 		/* 160x120 */
5813145efcdSJacopo Mondi 		.id		= OV5640_MODE_QQVGA_160_120,
5823145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
5833145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
5845113d5b3SJacopo Mondi 		.width		= 160,
5855113d5b3SJacopo Mondi 		.height		= 120,
5865113d5b3SJacopo Mondi 		.dvp_timings = {
5873145efcdSJacopo Mondi 			.analog_crop = {
5883145efcdSJacopo Mondi 				.left	= 0,
5893145efcdSJacopo Mondi 				.top	= 4,
5903145efcdSJacopo Mondi 				.width	= 2624,
5913145efcdSJacopo Mondi 				.height	= 1944,
5923145efcdSJacopo Mondi 			},
5933145efcdSJacopo Mondi 			.crop = {
5943145efcdSJacopo Mondi 				.left	= 16,
5953145efcdSJacopo Mondi 				.top	= 6,
5963145efcdSJacopo Mondi 				.width	= 160,
5973145efcdSJacopo Mondi 				.height	= 120,
5983145efcdSJacopo Mondi 			},
5993145efcdSJacopo Mondi 			.htot		= 1896,
6003145efcdSJacopo Mondi 			.vblank_def	= 864,
6015113d5b3SJacopo Mondi 		},
6025113d5b3SJacopo Mondi 		.csi2_timings = {
6035113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
6045113d5b3SJacopo Mondi 			.analog_crop = {
6055113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
6065113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
6075113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
6085113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
6095113d5b3SJacopo Mondi 			},
6105113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
6115113d5b3SJacopo Mondi 			.crop = {
6125113d5b3SJacopo Mondi 				.left	= 2,
6135113d5b3SJacopo Mondi 				.top	= 4,
6145113d5b3SJacopo Mondi 				.width	= 160,
6155113d5b3SJacopo Mondi 				.height	= 120,
6165113d5b3SJacopo Mondi 			},
617961bed9fSJacopo Mondi 			.htot		= 1600,
618961bed9fSJacopo Mondi 			.vblank_def	= 878,
6195113d5b3SJacopo Mondi 		},
620db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
621db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
62219f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
62319f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
6248409d017SJacopo Mondi 	}, {
6258409d017SJacopo Mondi 		/* 176x144 */
6263145efcdSJacopo Mondi 		.id		= OV5640_MODE_QCIF_176_144,
6273145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
6283145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
6295113d5b3SJacopo Mondi 		.width		= 176,
6305113d5b3SJacopo Mondi 		.height		= 144,
6315113d5b3SJacopo Mondi 		.dvp_timings = {
6323145efcdSJacopo Mondi 			.analog_crop = {
6333145efcdSJacopo Mondi 				.left	= 0,
6343145efcdSJacopo Mondi 				.top	= 4,
6353145efcdSJacopo Mondi 				.width	= 2624,
6363145efcdSJacopo Mondi 				.height	= 1944,
6373145efcdSJacopo Mondi 			},
6383145efcdSJacopo Mondi 			.crop = {
6393145efcdSJacopo Mondi 				.left	= 16,
6403145efcdSJacopo Mondi 				.top	= 6,
6413145efcdSJacopo Mondi 				.width	= 176,
6423145efcdSJacopo Mondi 				.height	= 144,
6433145efcdSJacopo Mondi 			},
6443145efcdSJacopo Mondi 			.htot		= 1896,
6453145efcdSJacopo Mondi 			.vblank_def	= 840,
6465113d5b3SJacopo Mondi 		},
6475113d5b3SJacopo Mondi 		.csi2_timings = {
6485113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
6495113d5b3SJacopo Mondi 			.analog_crop = {
6505113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
6515113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
6525113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
6535113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
6545113d5b3SJacopo Mondi 			},
6555113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
6565113d5b3SJacopo Mondi 			.crop = {
6575113d5b3SJacopo Mondi 				.left	= 2,
6585113d5b3SJacopo Mondi 				.top	= 4,
6595113d5b3SJacopo Mondi 				.width	= 176,
6605113d5b3SJacopo Mondi 				.height	= 144,
6615113d5b3SJacopo Mondi 			},
662961bed9fSJacopo Mondi 			.htot		= 1600,
663961bed9fSJacopo Mondi 			.vblank_def	= 854,
6645113d5b3SJacopo Mondi 		},
665db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
666db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
66719f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
66819f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
6698409d017SJacopo Mondi 	}, {
6708409d017SJacopo Mondi 		/* 320x240 */
6713145efcdSJacopo Mondi 		.id		= OV5640_MODE_QVGA_320_240,
6723145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
6735113d5b3SJacopo Mondi 		.width		= 320,
6745113d5b3SJacopo Mondi 		.height		= 240,
6753145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
6765113d5b3SJacopo Mondi 		.dvp_timings = {
6773145efcdSJacopo Mondi 			.analog_crop = {
6783145efcdSJacopo Mondi 				.left	= 0,
6793145efcdSJacopo Mondi 				.top	= 4,
6803145efcdSJacopo Mondi 				.width	= 2624,
6813145efcdSJacopo Mondi 				.height	= 1944,
6823145efcdSJacopo Mondi 			},
6833145efcdSJacopo Mondi 			.crop = {
6843145efcdSJacopo Mondi 				.left	= 16,
6853145efcdSJacopo Mondi 				.top	= 6,
6863145efcdSJacopo Mondi 				.width	= 320,
6873145efcdSJacopo Mondi 				.height	= 240,
6883145efcdSJacopo Mondi 			},
6893145efcdSJacopo Mondi 			.htot		= 1896,
6903145efcdSJacopo Mondi 			.vblank_def	= 744,
6915113d5b3SJacopo Mondi 		},
6925113d5b3SJacopo Mondi 		.csi2_timings = {
6935113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
6945113d5b3SJacopo Mondi 			.analog_crop = {
6955113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
6965113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
6975113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
6985113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
6995113d5b3SJacopo Mondi 			},
7005113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
7015113d5b3SJacopo Mondi 			.crop = {
7025113d5b3SJacopo Mondi 				.left	= 2,
7035113d5b3SJacopo Mondi 				.top	= 4,
7045113d5b3SJacopo Mondi 				.width	= 320,
7055113d5b3SJacopo Mondi 				.height	= 240,
7065113d5b3SJacopo Mondi 			},
707961bed9fSJacopo Mondi 			.htot		= 1600,
708961bed9fSJacopo Mondi 			.vblank_def	= 760,
7095113d5b3SJacopo Mondi 		},
710db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
711db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
71219f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
71319f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
7148409d017SJacopo Mondi 	}, {
7158409d017SJacopo Mondi 		/* 640x480 */
7163145efcdSJacopo Mondi 		.id		= OV5640_MODE_VGA_640_480,
7173145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
7183145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
7195113d5b3SJacopo Mondi 		.width		= 640,
7205113d5b3SJacopo Mondi 		.height		= 480,
7215113d5b3SJacopo Mondi 		.dvp_timings = {
7223145efcdSJacopo Mondi 			.analog_crop = {
7233145efcdSJacopo Mondi 				.left	= 0,
7243145efcdSJacopo Mondi 				.top	= 4,
7253145efcdSJacopo Mondi 				.width	= 2624,
7263145efcdSJacopo Mondi 				.height	= 1944,
7273145efcdSJacopo Mondi 			},
7283145efcdSJacopo Mondi 			.crop = {
7293145efcdSJacopo Mondi 				.left	= 16,
7303145efcdSJacopo Mondi 				.top	= 6,
7313145efcdSJacopo Mondi 				.width	= 640,
7323145efcdSJacopo Mondi 				.height	= 480,
7333145efcdSJacopo Mondi 			},
7343145efcdSJacopo Mondi 			.htot		= 1896,
7353145efcdSJacopo Mondi 			.vblank_def	= 600,
7365113d5b3SJacopo Mondi 		},
7375113d5b3SJacopo Mondi 		.csi2_timings = {
7385113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
7395113d5b3SJacopo Mondi 			.analog_crop = {
7405113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
7415113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
7425113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
7435113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
7445113d5b3SJacopo Mondi 			},
7455113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
7465113d5b3SJacopo Mondi 			.crop = {
7475113d5b3SJacopo Mondi 				.left	= 2,
7485113d5b3SJacopo Mondi 				.top	= 4,
7495113d5b3SJacopo Mondi 				.width	= 640,
7505113d5b3SJacopo Mondi 				.height	= 480,
7515113d5b3SJacopo Mondi 			},
752961bed9fSJacopo Mondi 			.htot		= 1600,
753961bed9fSJacopo Mondi 			.vblank_def	= 520,
7545113d5b3SJacopo Mondi 		},
755db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
756db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
75719f2e3e6SHugues Fruchet 		.max_fps	= OV5640_60_FPS,
75819f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
7598409d017SJacopo Mondi 	}, {
7608409d017SJacopo Mondi 		/* 720x480 */
7613145efcdSJacopo Mondi 		.id		= OV5640_MODE_NTSC_720_480,
7623145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
7635113d5b3SJacopo Mondi 		.width		= 720,
7645113d5b3SJacopo Mondi 		.height		= 480,
7653145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
7665113d5b3SJacopo Mondi 		.dvp_timings = {
7673145efcdSJacopo Mondi 			.analog_crop = {
7683145efcdSJacopo Mondi 				.left	= 0,
7693145efcdSJacopo Mondi 				.top	= 4,
7703145efcdSJacopo Mondi 				.width	= 2624,
7713145efcdSJacopo Mondi 				.height	= 1944,
7723145efcdSJacopo Mondi 			},
7733145efcdSJacopo Mondi 			.crop = {
774e74ef55bSJacopo Mondi 				.left	= 56,
7753145efcdSJacopo Mondi 				.top	= 60,
7763145efcdSJacopo Mondi 				.width	= 720,
7773145efcdSJacopo Mondi 				.height	= 480,
7783145efcdSJacopo Mondi 			},
7793145efcdSJacopo Mondi 			.htot		= 1896,
7803145efcdSJacopo Mondi 			.vblank_def	= 504,
7815113d5b3SJacopo Mondi 		},
7825113d5b3SJacopo Mondi 		.csi2_timings = {
7835113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
7845113d5b3SJacopo Mondi 			.analog_crop = {
7855113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
7865113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
7875113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
7885113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
7895113d5b3SJacopo Mondi 			},
7905113d5b3SJacopo Mondi 			.crop = {
7915113d5b3SJacopo Mondi 				.left	= 56,
7925113d5b3SJacopo Mondi 				.top	= 60,
7935113d5b3SJacopo Mondi 				.width	= 720,
7945113d5b3SJacopo Mondi 				.height	= 480,
7955113d5b3SJacopo Mondi 			},
7965113d5b3SJacopo Mondi 			.htot		= 1896,
797961bed9fSJacopo Mondi 			.vblank_def	= 1206,
7985113d5b3SJacopo Mondi 		},
799db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
800db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
80119f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
80219f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
8038409d017SJacopo Mondi 	}, {
8048409d017SJacopo Mondi 		/* 720x576 */
8053145efcdSJacopo Mondi 		.id		= OV5640_MODE_PAL_720_576,
8063145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
8075113d5b3SJacopo Mondi 		.width		= 720,
8085113d5b3SJacopo Mondi 		.height		= 576,
8093145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
8105113d5b3SJacopo Mondi 		.dvp_timings = {
8113145efcdSJacopo Mondi 			.analog_crop = {
8123145efcdSJacopo Mondi 				.left	= 0,
8133145efcdSJacopo Mondi 				.top	= 4,
8143145efcdSJacopo Mondi 				.width	= 2624,
8153145efcdSJacopo Mondi 				.height	= 1944,
8163145efcdSJacopo Mondi 			},
8173145efcdSJacopo Mondi 			.crop = {
8183145efcdSJacopo Mondi 				.left	= 56,
8193145efcdSJacopo Mondi 				.top	= 6,
8203145efcdSJacopo Mondi 				.width	= 720,
8213145efcdSJacopo Mondi 				.height	= 576,
8223145efcdSJacopo Mondi 			},
8233145efcdSJacopo Mondi 			.htot		= 1896,
8243145efcdSJacopo Mondi 			.vblank_def	= 408,
8255113d5b3SJacopo Mondi 		},
8265113d5b3SJacopo Mondi 		.csi2_timings = {
8275113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
8285113d5b3SJacopo Mondi 			.analog_crop = {
8295113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
8305113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
8315113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
8325113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
8335113d5b3SJacopo Mondi 			},
8345113d5b3SJacopo Mondi 			.crop = {
8355113d5b3SJacopo Mondi 				.left	= 56,
8365113d5b3SJacopo Mondi 				.top	= 6,
8375113d5b3SJacopo Mondi 				.width	= 720,
8385113d5b3SJacopo Mondi 				.height	= 576,
8395113d5b3SJacopo Mondi 			},
8405113d5b3SJacopo Mondi 			.htot		= 1896,
841961bed9fSJacopo Mondi 			.vblank_def	= 1110,
8425113d5b3SJacopo Mondi 		},
843db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
844db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
84519f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
84619f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
8478409d017SJacopo Mondi 	}, {
8488409d017SJacopo Mondi 		/* 1024x768 */
8493145efcdSJacopo Mondi 		.id		= OV5640_MODE_XGA_1024_768,
8503145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
8513145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
8525113d5b3SJacopo Mondi 		.width		= 1024,
8535113d5b3SJacopo Mondi 		.height		= 768,
8545113d5b3SJacopo Mondi 		.dvp_timings = {
8553145efcdSJacopo Mondi 			.analog_crop = {
8563145efcdSJacopo Mondi 				.left	= 0,
8573145efcdSJacopo Mondi 				.top	= 4,
8583145efcdSJacopo Mondi 				.width	= 2624,
8593145efcdSJacopo Mondi 				.height	= 1944,
8603145efcdSJacopo Mondi 			},
8613145efcdSJacopo Mondi 			.crop = {
8623145efcdSJacopo Mondi 				.left	= 16,
8633145efcdSJacopo Mondi 				.top	= 6,
8643145efcdSJacopo Mondi 				.width	= 1024,
8653145efcdSJacopo Mondi 				.height	= 768,
8663145efcdSJacopo Mondi 			},
8673145efcdSJacopo Mondi 			.htot		= 1896,
8683145efcdSJacopo Mondi 			.vblank_def	= 312,
8695113d5b3SJacopo Mondi 		},
8705113d5b3SJacopo Mondi 		.csi2_timings = {
8715113d5b3SJacopo Mondi 			.analog_crop = {
8725113d5b3SJacopo Mondi 				.left	= 0,
8735113d5b3SJacopo Mondi 				.top	= 4,
8745113d5b3SJacopo Mondi 				.width	= OV5640_NATIVE_WIDTH,
8755113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
8765113d5b3SJacopo Mondi 			},
8775113d5b3SJacopo Mondi 			.crop = {
8785113d5b3SJacopo Mondi 				.left	= 16,
8795113d5b3SJacopo Mondi 				.top	= 6,
8805113d5b3SJacopo Mondi 				.width	= 1024,
8815113d5b3SJacopo Mondi 				.height	= 768,
8825113d5b3SJacopo Mondi 			},
8835113d5b3SJacopo Mondi 			.htot		= 1896,
884961bed9fSJacopo Mondi 			.vblank_def	= 918,
8855113d5b3SJacopo Mondi 		},
886db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
887db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
88819f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
88919f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
8908409d017SJacopo Mondi 	}, {
8918409d017SJacopo Mondi 		/* 1280x720 */
8923145efcdSJacopo Mondi 		.id		= OV5640_MODE_720P_1280_720,
8933145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
8943145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_124M,
8955113d5b3SJacopo Mondi 		.width		= 1280,
8965113d5b3SJacopo Mondi 		.height		= 720,
8975113d5b3SJacopo Mondi 		.dvp_timings = {
8983145efcdSJacopo Mondi 			.analog_crop = {
8993145efcdSJacopo Mondi 				.left	= 0,
9003145efcdSJacopo Mondi 				.top	= 250,
9013145efcdSJacopo Mondi 				.width	= 2624,
9023145efcdSJacopo Mondi 				.height	= 1456,
9033145efcdSJacopo Mondi 			},
9043145efcdSJacopo Mondi 			.crop = {
9053145efcdSJacopo Mondi 				.left	= 16,
9063145efcdSJacopo Mondi 				.top	= 4,
9073145efcdSJacopo Mondi 				.width	= 1280,
9083145efcdSJacopo Mondi 				.height	= 720,
9093145efcdSJacopo Mondi 			},
9103145efcdSJacopo Mondi 			.htot		= 1892,
9113145efcdSJacopo Mondi 			.vblank_def	= 20,
9125113d5b3SJacopo Mondi 		},
9135113d5b3SJacopo Mondi 		.csi2_timings = {
9145113d5b3SJacopo Mondi 			.analog_crop = {
9155113d5b3SJacopo Mondi 				.left	= 0,
9165113d5b3SJacopo Mondi 				.top	= 250,
9175113d5b3SJacopo Mondi 				.width	= 2624,
9185113d5b3SJacopo Mondi 				.height	= 1456,
9195113d5b3SJacopo Mondi 			},
9205113d5b3SJacopo Mondi 			.crop = {
9215113d5b3SJacopo Mondi 				.left	= 16,
9225113d5b3SJacopo Mondi 				.top	= 4,
9235113d5b3SJacopo Mondi 				.width	= 1280,
9245113d5b3SJacopo Mondi 				.height	= 720,
9255113d5b3SJacopo Mondi 			},
926961bed9fSJacopo Mondi 			.htot		= 1600,
927961bed9fSJacopo Mondi 			.vblank_def	= 560,
9285113d5b3SJacopo Mondi 		},
9293145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_720P_1280_720,
9303145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_720P_1280_720),
93119f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
93219f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
9338409d017SJacopo Mondi 	}, {
9348409d017SJacopo Mondi 		/* 1920x1080 */
9353145efcdSJacopo Mondi 		.id		= OV5640_MODE_1080P_1920_1080,
9363145efcdSJacopo Mondi 		.dn_mode	= SCALING,
9373145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_148M,
9385113d5b3SJacopo Mondi 		.width		= 1920,
9395113d5b3SJacopo Mondi 		.height		= 1080,
9405113d5b3SJacopo Mondi 		.dvp_timings = {
9413145efcdSJacopo Mondi 			.analog_crop = {
9423145efcdSJacopo Mondi 				.left	= 336,
9433145efcdSJacopo Mondi 				.top	= 434,
9443145efcdSJacopo Mondi 				.width	= 1952,
9453145efcdSJacopo Mondi 				.height	= 1088,
9463145efcdSJacopo Mondi 			},
9473145efcdSJacopo Mondi 			.crop = {
9483145efcdSJacopo Mondi 				.left	= 16,
9493145efcdSJacopo Mondi 				.top	= 4,
9503145efcdSJacopo Mondi 				.width	= 1920,
9513145efcdSJacopo Mondi 				.height	= 1080,
9523145efcdSJacopo Mondi 			},
9533145efcdSJacopo Mondi 			.htot		= 2500,
9543145efcdSJacopo Mondi 			.vblank_def	= 40,
9555113d5b3SJacopo Mondi 		},
9565113d5b3SJacopo Mondi 		.csi2_timings = {
9575113d5b3SJacopo Mondi 			/* Crop the full valid pixel array in the center. */
9585113d5b3SJacopo Mondi 			.analog_crop = {
9595113d5b3SJacopo Mondi 				.left	= 336,
9605113d5b3SJacopo Mondi 				.top	= 434,
9615113d5b3SJacopo Mondi 				.width	= 1952,
9625113d5b3SJacopo Mondi 				.height	= 1088,
9635113d5b3SJacopo Mondi 			},
9645113d5b3SJacopo Mondi 			/* Maintain a larger processing margins. */
9655113d5b3SJacopo Mondi 			.crop = {
9665113d5b3SJacopo Mondi 				.left	= 16,
9675113d5b3SJacopo Mondi 				.top	= 4,
9685113d5b3SJacopo Mondi 				.width	= 1920,
9695113d5b3SJacopo Mondi 				.height	= 1080,
9705113d5b3SJacopo Mondi 			},
971961bed9fSJacopo Mondi 			.htot		= 2234,
972961bed9fSJacopo Mondi 			.vblank_def	= 24,
9735113d5b3SJacopo Mondi 		},
9743145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_1080P_1920_1080,
9753145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_1080P_1920_1080),
97619f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
97719f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
9788409d017SJacopo Mondi 	}, {
9798409d017SJacopo Mondi 		/* 2592x1944 */
9803145efcdSJacopo Mondi 		.id		= OV5640_MODE_QSXGA_2592_1944,
9813145efcdSJacopo Mondi 		.dn_mode	= SCALING,
9823145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_168M,
9835113d5b3SJacopo Mondi 		.width		= OV5640_PIXEL_ARRAY_WIDTH,
9845113d5b3SJacopo Mondi 		.height		= OV5640_PIXEL_ARRAY_HEIGHT,
9855113d5b3SJacopo Mondi 		.dvp_timings = {
9863145efcdSJacopo Mondi 			.analog_crop = {
9873145efcdSJacopo Mondi 				.left	= 0,
9883145efcdSJacopo Mondi 				.top	= 0,
9893145efcdSJacopo Mondi 				.width	= 2624,
9903145efcdSJacopo Mondi 				.height	= 1952,
9913145efcdSJacopo Mondi 			},
9923145efcdSJacopo Mondi 			.crop = {
9933145efcdSJacopo Mondi 				.left	= 16,
9943145efcdSJacopo Mondi 				.top	= 4,
9953145efcdSJacopo Mondi 				.width	= 2592,
9963145efcdSJacopo Mondi 				.height	= 1944,
9973145efcdSJacopo Mondi 			},
9983145efcdSJacopo Mondi 			.htot		= 2844,
9993145efcdSJacopo Mondi 			.vblank_def	= 24,
10005113d5b3SJacopo Mondi 		},
10015113d5b3SJacopo Mondi 		.csi2_timings = {
10025113d5b3SJacopo Mondi 			/* Give more processing margin to full resolution. */
10035113d5b3SJacopo Mondi 			.analog_crop = {
10045113d5b3SJacopo Mondi 				.left	= 0,
10055113d5b3SJacopo Mondi 				.top	= 0,
10065113d5b3SJacopo Mondi 				.width	= OV5640_NATIVE_WIDTH,
10075113d5b3SJacopo Mondi 				.height	= 1952,
10085113d5b3SJacopo Mondi 			},
10095113d5b3SJacopo Mondi 			.crop = {
10105113d5b3SJacopo Mondi 				.left	= 16,
10115113d5b3SJacopo Mondi 				.top	= 4,
10125113d5b3SJacopo Mondi 				.width	= 2592,
10135113d5b3SJacopo Mondi 				.height	= 1944,
10145113d5b3SJacopo Mondi 			},
10155113d5b3SJacopo Mondi 			.htot		= 2844,
10165113d5b3SJacopo Mondi 			.vblank_def	= 24,
10175113d5b3SJacopo Mondi 		},
10183145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_QSXGA_2592_1944,
10193145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_QSXGA_2592_1944),
102019f2e3e6SHugues Fruchet 		.max_fps	= OV5640_15_FPS,
102119f2e3e6SHugues Fruchet 		.def_fps	= OV5640_15_FPS
10228409d017SJacopo Mondi 	},
102319a81c14SSteve Longerbeam };
102419a81c14SSteve Longerbeam 
10252de6bb97SJacopo Mondi static const struct ov5640_timings *
10262de6bb97SJacopo Mondi ov5640_timings(const struct ov5640_dev *sensor,
10272de6bb97SJacopo Mondi 	       const struct ov5640_mode_info *mode)
10282de6bb97SJacopo Mondi {
10292de6bb97SJacopo Mondi 	if (ov5640_is_csi2(sensor))
10302de6bb97SJacopo Mondi 		return &mode->csi2_timings;
10312de6bb97SJacopo Mondi 
10322de6bb97SJacopo Mondi 	return &mode->dvp_timings;
10332de6bb97SJacopo Mondi }
10342de6bb97SJacopo Mondi 
103519a81c14SSteve Longerbeam static int ov5640_init_slave_id(struct ov5640_dev *sensor)
103619a81c14SSteve Longerbeam {
103719a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
103819a81c14SSteve Longerbeam 	struct i2c_msg msg;
103919a81c14SSteve Longerbeam 	u8 buf[3];
104019a81c14SSteve Longerbeam 	int ret;
104119a81c14SSteve Longerbeam 
104219a81c14SSteve Longerbeam 	if (client->addr == OV5640_DEFAULT_SLAVE_ID)
104319a81c14SSteve Longerbeam 		return 0;
104419a81c14SSteve Longerbeam 
104519a81c14SSteve Longerbeam 	buf[0] = OV5640_REG_SLAVE_ID >> 8;
104619a81c14SSteve Longerbeam 	buf[1] = OV5640_REG_SLAVE_ID & 0xff;
104719a81c14SSteve Longerbeam 	buf[2] = client->addr << 1;
104819a81c14SSteve Longerbeam 
104919a81c14SSteve Longerbeam 	msg.addr = OV5640_DEFAULT_SLAVE_ID;
105019a81c14SSteve Longerbeam 	msg.flags = 0;
105119a81c14SSteve Longerbeam 	msg.buf = buf;
105219a81c14SSteve Longerbeam 	msg.len = sizeof(buf);
105319a81c14SSteve Longerbeam 
105419a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, &msg, 1);
105519a81c14SSteve Longerbeam 	if (ret < 0) {
105619a81c14SSteve Longerbeam 		dev_err(&client->dev, "%s: failed with %d\n", __func__, ret);
105719a81c14SSteve Longerbeam 		return ret;
105819a81c14SSteve Longerbeam 	}
105919a81c14SSteve Longerbeam 
106019a81c14SSteve Longerbeam 	return 0;
106119a81c14SSteve Longerbeam }
106219a81c14SSteve Longerbeam 
106319a81c14SSteve Longerbeam static int ov5640_write_reg(struct ov5640_dev *sensor, u16 reg, u8 val)
106419a81c14SSteve Longerbeam {
106519a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
106619a81c14SSteve Longerbeam 	struct i2c_msg msg;
106719a81c14SSteve Longerbeam 	u8 buf[3];
106819a81c14SSteve Longerbeam 	int ret;
106919a81c14SSteve Longerbeam 
107019a81c14SSteve Longerbeam 	buf[0] = reg >> 8;
107119a81c14SSteve Longerbeam 	buf[1] = reg & 0xff;
107219a81c14SSteve Longerbeam 	buf[2] = val;
107319a81c14SSteve Longerbeam 
107419a81c14SSteve Longerbeam 	msg.addr = client->addr;
107519a81c14SSteve Longerbeam 	msg.flags = client->flags;
107619a81c14SSteve Longerbeam 	msg.buf = buf;
107719a81c14SSteve Longerbeam 	msg.len = sizeof(buf);
107819a81c14SSteve Longerbeam 
107919a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, &msg, 1);
108019a81c14SSteve Longerbeam 	if (ret < 0) {
10813924c623SHugues Fruchet 		dev_err(&client->dev, "%s: error: reg=%x, val=%x\n",
108219a81c14SSteve Longerbeam 			__func__, reg, val);
108319a81c14SSteve Longerbeam 		return ret;
108419a81c14SSteve Longerbeam 	}
108519a81c14SSteve Longerbeam 
108619a81c14SSteve Longerbeam 	return 0;
108719a81c14SSteve Longerbeam }
108819a81c14SSteve Longerbeam 
108919a81c14SSteve Longerbeam static int ov5640_read_reg(struct ov5640_dev *sensor, u16 reg, u8 *val)
109019a81c14SSteve Longerbeam {
109119a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
109219a81c14SSteve Longerbeam 	struct i2c_msg msg[2];
109319a81c14SSteve Longerbeam 	u8 buf[2];
109419a81c14SSteve Longerbeam 	int ret;
109519a81c14SSteve Longerbeam 
109619a81c14SSteve Longerbeam 	buf[0] = reg >> 8;
109719a81c14SSteve Longerbeam 	buf[1] = reg & 0xff;
109819a81c14SSteve Longerbeam 
109919a81c14SSteve Longerbeam 	msg[0].addr = client->addr;
110019a81c14SSteve Longerbeam 	msg[0].flags = client->flags;
110119a81c14SSteve Longerbeam 	msg[0].buf = buf;
110219a81c14SSteve Longerbeam 	msg[0].len = sizeof(buf);
110319a81c14SSteve Longerbeam 
110419a81c14SSteve Longerbeam 	msg[1].addr = client->addr;
110519a81c14SSteve Longerbeam 	msg[1].flags = client->flags | I2C_M_RD;
110619a81c14SSteve Longerbeam 	msg[1].buf = buf;
110719a81c14SSteve Longerbeam 	msg[1].len = 1;
110819a81c14SSteve Longerbeam 
110919a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, msg, 2);
11103924c623SHugues Fruchet 	if (ret < 0) {
11113924c623SHugues Fruchet 		dev_err(&client->dev, "%s: error: reg=%x\n",
11123924c623SHugues Fruchet 			__func__, reg);
111319a81c14SSteve Longerbeam 		return ret;
11143924c623SHugues Fruchet 	}
111519a81c14SSteve Longerbeam 
111619a81c14SSteve Longerbeam 	*val = buf[0];
111719a81c14SSteve Longerbeam 	return 0;
111819a81c14SSteve Longerbeam }
111919a81c14SSteve Longerbeam 
112019a81c14SSteve Longerbeam static int ov5640_read_reg16(struct ov5640_dev *sensor, u16 reg, u16 *val)
112119a81c14SSteve Longerbeam {
112219a81c14SSteve Longerbeam 	u8 hi, lo;
112319a81c14SSteve Longerbeam 	int ret;
112419a81c14SSteve Longerbeam 
112519a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg, &hi);
112619a81c14SSteve Longerbeam 	if (ret)
112719a81c14SSteve Longerbeam 		return ret;
112819a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg + 1, &lo);
112919a81c14SSteve Longerbeam 	if (ret)
113019a81c14SSteve Longerbeam 		return ret;
113119a81c14SSteve Longerbeam 
113219a81c14SSteve Longerbeam 	*val = ((u16)hi << 8) | (u16)lo;
113319a81c14SSteve Longerbeam 	return 0;
113419a81c14SSteve Longerbeam }
113519a81c14SSteve Longerbeam 
113619a81c14SSteve Longerbeam static int ov5640_write_reg16(struct ov5640_dev *sensor, u16 reg, u16 val)
113719a81c14SSteve Longerbeam {
113819a81c14SSteve Longerbeam 	int ret;
113919a81c14SSteve Longerbeam 
114019a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, reg, val >> 8);
114119a81c14SSteve Longerbeam 	if (ret)
114219a81c14SSteve Longerbeam 		return ret;
114319a81c14SSteve Longerbeam 
114419a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, reg + 1, val & 0xff);
114519a81c14SSteve Longerbeam }
114619a81c14SSteve Longerbeam 
114719a81c14SSteve Longerbeam static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg,
114819a81c14SSteve Longerbeam 			  u8 mask, u8 val)
114919a81c14SSteve Longerbeam {
115019a81c14SSteve Longerbeam 	u8 readval;
115119a81c14SSteve Longerbeam 	int ret;
115219a81c14SSteve Longerbeam 
115319a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg, &readval);
115419a81c14SSteve Longerbeam 	if (ret)
115519a81c14SSteve Longerbeam 		return ret;
115619a81c14SSteve Longerbeam 
115719a81c14SSteve Longerbeam 	readval &= ~mask;
115819a81c14SSteve Longerbeam 	val &= mask;
115919a81c14SSteve Longerbeam 	val |= readval;
116019a81c14SSteve Longerbeam 
116119a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, reg, val);
116219a81c14SSteve Longerbeam }
116319a81c14SSteve Longerbeam 
1164aa288248SMaxime Ripard /*
1165aa288248SMaxime Ripard  * After trying the various combinations, reading various
1166f8a7647dSMauro Carvalho Chehab  * documentations spread around the net, and from the various
1167aa288248SMaxime Ripard  * feedback, the clock tree is probably as follows:
1168aa288248SMaxime Ripard  *
1169aa288248SMaxime Ripard  *   +--------------+
1170aa288248SMaxime Ripard  *   |  Ext. Clock  |
1171aa288248SMaxime Ripard  *   +-+------------+
1172aa288248SMaxime Ripard  *     |  +----------+
1173aa288248SMaxime Ripard  *     +->|   PLL1   | - reg 0x3036, for the multiplier
1174aa288248SMaxime Ripard  *        +-+--------+ - reg 0x3037, bits 0-3 for the pre-divider
1175aa288248SMaxime Ripard  *          |  +--------------+
1176aa288248SMaxime Ripard  *          +->| System Clock |  - reg 0x3035, bits 4-7
1177aa288248SMaxime Ripard  *             +-+------------+
1178aa288248SMaxime Ripard  *               |  +--------------+
1179aa288248SMaxime Ripard  *               +->| MIPI Divider | - reg 0x3035, bits 0-3
1180aa288248SMaxime Ripard  *               |  +-+------------+
1181aa288248SMaxime Ripard  *               |    +----------------> MIPI SCLK
1182aa288248SMaxime Ripard  *               |    +  +-----+
1183aa288248SMaxime Ripard  *               |    +->| / 2 |-------> MIPI BIT CLK
1184aa288248SMaxime Ripard  *               |       +-----+
1185aa288248SMaxime Ripard  *               |  +--------------+
1186aa288248SMaxime Ripard  *               +->| PLL Root Div | - reg 0x3037, bit 4
1187aa288248SMaxime Ripard  *                  +-+------------+
1188aa288248SMaxime Ripard  *                    |  +---------+
11894c85f628SPaul Kocialkowski  *                    +->| Bit Div | - reg 0x3034, bits 0-3
1190aa288248SMaxime Ripard  *                       +-+-------+
1191aa288248SMaxime Ripard  *                         |  +-------------+
1192aa288248SMaxime Ripard  *                         +->| SCLK Div    | - reg 0x3108, bits 0-1
1193aa288248SMaxime Ripard  *                         |  +-+-----------+
1194aa288248SMaxime Ripard  *                         |    +---------------> SCLK
1195aa288248SMaxime Ripard  *                         |  +-------------+
1196aa288248SMaxime Ripard  *                         +->| SCLK 2X Div | - reg 0x3108, bits 2-3
1197aa288248SMaxime Ripard  *                         |  +-+-----------+
1198aa288248SMaxime Ripard  *                         |    +---------------> SCLK 2X
1199aa288248SMaxime Ripard  *                         |  +-------------+
1200aa288248SMaxime Ripard  *                         +->| PCLK Div    | - reg 0x3108, bits 4-5
1201aa288248SMaxime Ripard  *                            ++------------+
1202aa288248SMaxime Ripard  *                             +  +-----------+
1203aa288248SMaxime Ripard  *                             +->|   P_DIV   | - reg 0x3035, bits 0-3
1204aa288248SMaxime Ripard  *                                +-----+-----+
1205aa288248SMaxime Ripard  *                                       +------------> PCLK
1206aa288248SMaxime Ripard  *
12076c957ed7SJacopo Mondi  * There seems to be also constraints:
1208aa288248SMaxime Ripard  *  - the PLL pre-divider output rate should be in the 4-27MHz range
1209aa288248SMaxime Ripard  *  - the PLL multiplier output rate should be in the 500-1000MHz range
1210aa288248SMaxime Ripard  *  - PCLK >= SCLK * 2 in YUV, >= SCLK in Raw or JPEG
1211aa288248SMaxime Ripard  */
1212aa288248SMaxime Ripard 
1213aa288248SMaxime Ripard /*
1214aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1215aa288248SMaxime Ripard  * set to 3 in the vendor kernels.
1216aa288248SMaxime Ripard  */
1217aa288248SMaxime Ripard #define OV5640_PLL_PREDIV	3
1218aa288248SMaxime Ripard 
1219aa288248SMaxime Ripard #define OV5640_PLL_MULT_MIN	4
1220aa288248SMaxime Ripard #define OV5640_PLL_MULT_MAX	252
1221aa288248SMaxime Ripard 
1222aa288248SMaxime Ripard /*
1223aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 16, but the value is
1224aa288248SMaxime Ripard  * always set to either 1 or 2 in the vendor kernels.
1225aa288248SMaxime Ripard  */
1226aa288248SMaxime Ripard #define OV5640_SYSDIV_MIN	1
1227aa288248SMaxime Ripard #define OV5640_SYSDIV_MAX	16
1228aa288248SMaxime Ripard 
1229aa288248SMaxime Ripard /*
1230aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 2, but the value is always
1231aa288248SMaxime Ripard  * set to 2 in the vendor kernels.
1232aa288248SMaxime Ripard  */
1233aa288248SMaxime Ripard #define OV5640_PLL_ROOT_DIV			2
1234aa288248SMaxime Ripard #define OV5640_PLL_CTRL3_PLL_ROOT_DIV_2		BIT(4)
1235aa288248SMaxime Ripard 
1236aa288248SMaxime Ripard /*
1237aa288248SMaxime Ripard  * We only supports 8-bit formats at the moment
1238aa288248SMaxime Ripard  */
1239aa288248SMaxime Ripard #define OV5640_BIT_DIV				2
1240aa288248SMaxime Ripard #define OV5640_PLL_CTRL0_MIPI_MODE_8BIT		0x08
1241aa288248SMaxime Ripard 
1242aa288248SMaxime Ripard /*
1243aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1244aa288248SMaxime Ripard  * set to 2 in the vendor kernels.
1245aa288248SMaxime Ripard  */
1246aa288248SMaxime Ripard #define OV5640_SCLK_ROOT_DIV	2
1247aa288248SMaxime Ripard 
1248aa288248SMaxime Ripard /*
1249aa288248SMaxime Ripard  * This is hardcoded so that the consistency is maintained between SCLK and
1250aa288248SMaxime Ripard  * SCLK 2x.
1251aa288248SMaxime Ripard  */
1252aa288248SMaxime Ripard #define OV5640_SCLK2X_ROOT_DIV (OV5640_SCLK_ROOT_DIV / 2)
1253aa288248SMaxime Ripard 
1254aa288248SMaxime Ripard /*
1255aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1256aa288248SMaxime Ripard  * set to 1 in the vendor kernels.
1257aa288248SMaxime Ripard  */
1258aa288248SMaxime Ripard #define OV5640_PCLK_ROOT_DIV			1
1259aa288248SMaxime Ripard #define OV5640_PLL_SYS_ROOT_DIVIDER_BYPASS	0x00
1260aa288248SMaxime Ripard 
1261aa288248SMaxime Ripard static unsigned long ov5640_compute_sys_clk(struct ov5640_dev *sensor,
1262aa288248SMaxime Ripard 					    u8 pll_prediv, u8 pll_mult,
1263aa288248SMaxime Ripard 					    u8 sysdiv)
1264aa288248SMaxime Ripard {
1265aa288248SMaxime Ripard 	unsigned long sysclk = sensor->xclk_freq / pll_prediv * pll_mult;
1266aa288248SMaxime Ripard 
1267aa288248SMaxime Ripard 	/* PLL1 output cannot exceed 1GHz. */
1268aa288248SMaxime Ripard 	if (sysclk / 1000000 > 1000)
1269aa288248SMaxime Ripard 		return 0;
1270aa288248SMaxime Ripard 
1271aa288248SMaxime Ripard 	return sysclk / sysdiv;
1272aa288248SMaxime Ripard }
1273aa288248SMaxime Ripard 
1274aa288248SMaxime Ripard static unsigned long ov5640_calc_sys_clk(struct ov5640_dev *sensor,
1275aa288248SMaxime Ripard 					 unsigned long rate,
1276aa288248SMaxime Ripard 					 u8 *pll_prediv, u8 *pll_mult,
1277aa288248SMaxime Ripard 					 u8 *sysdiv)
1278aa288248SMaxime Ripard {
1279aa288248SMaxime Ripard 	unsigned long best = ~0;
1280aa288248SMaxime Ripard 	u8 best_sysdiv = 1, best_mult = 1;
1281aa288248SMaxime Ripard 	u8 _sysdiv, _pll_mult;
1282aa288248SMaxime Ripard 
1283aa288248SMaxime Ripard 	for (_sysdiv = OV5640_SYSDIV_MIN;
1284aa288248SMaxime Ripard 	     _sysdiv <= OV5640_SYSDIV_MAX;
1285aa288248SMaxime Ripard 	     _sysdiv++) {
1286aa288248SMaxime Ripard 		for (_pll_mult = OV5640_PLL_MULT_MIN;
1287aa288248SMaxime Ripard 		     _pll_mult <= OV5640_PLL_MULT_MAX;
1288aa288248SMaxime Ripard 		     _pll_mult++) {
1289aa288248SMaxime Ripard 			unsigned long _rate;
1290aa288248SMaxime Ripard 
1291aa288248SMaxime Ripard 			/*
1292aa288248SMaxime Ripard 			 * The PLL multiplier cannot be odd if above
1293aa288248SMaxime Ripard 			 * 127.
1294aa288248SMaxime Ripard 			 */
1295aa288248SMaxime Ripard 			if (_pll_mult > 127 && (_pll_mult % 2))
1296aa288248SMaxime Ripard 				continue;
1297aa288248SMaxime Ripard 
1298aa288248SMaxime Ripard 			_rate = ov5640_compute_sys_clk(sensor,
1299aa288248SMaxime Ripard 						       OV5640_PLL_PREDIV,
1300aa288248SMaxime Ripard 						       _pll_mult, _sysdiv);
1301aa288248SMaxime Ripard 
1302aa288248SMaxime Ripard 			/*
1303aa288248SMaxime Ripard 			 * We have reached the maximum allowed PLL1 output,
1304aa288248SMaxime Ripard 			 * increase sysdiv.
1305aa288248SMaxime Ripard 			 */
13062e3df204SAdam Ford 			if (!_rate)
1307aa288248SMaxime Ripard 				break;
1308aa288248SMaxime Ripard 
1309aa288248SMaxime Ripard 			/*
1310aa288248SMaxime Ripard 			 * Prefer rates above the expected clock rate than
1311aa288248SMaxime Ripard 			 * below, even if that means being less precise.
1312aa288248SMaxime Ripard 			 */
1313aa288248SMaxime Ripard 			if (_rate < rate)
1314aa288248SMaxime Ripard 				continue;
1315aa288248SMaxime Ripard 
1316aa288248SMaxime Ripard 			if (abs(rate - _rate) < abs(rate - best)) {
1317aa288248SMaxime Ripard 				best = _rate;
1318aa288248SMaxime Ripard 				best_sysdiv = _sysdiv;
1319aa288248SMaxime Ripard 				best_mult = _pll_mult;
1320aa288248SMaxime Ripard 			}
1321aa288248SMaxime Ripard 
1322aa288248SMaxime Ripard 			if (_rate == rate)
1323aa288248SMaxime Ripard 				goto out;
1324aa288248SMaxime Ripard 		}
1325aa288248SMaxime Ripard 	}
1326aa288248SMaxime Ripard 
1327aa288248SMaxime Ripard out:
1328aa288248SMaxime Ripard 	*sysdiv = best_sysdiv;
1329aa288248SMaxime Ripard 	*pll_prediv = OV5640_PLL_PREDIV;
1330aa288248SMaxime Ripard 	*pll_mult = best_mult;
1331aa288248SMaxime Ripard 
1332aa288248SMaxime Ripard 	return best;
1333aa288248SMaxime Ripard }
1334aa288248SMaxime Ripard 
1335aa288248SMaxime Ripard /*
1336aa288248SMaxime Ripard  * ov5640_set_mipi_pclk() - Calculate the clock tree configuration values
1337aa288248SMaxime Ripard  *			    for the MIPI CSI-2 output.
1338aa288248SMaxime Ripard  */
13396c957ed7SJacopo Mondi static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor)
1340aa288248SMaxime Ripard {
13416c957ed7SJacopo Mondi 	u8 bit_div, mipi_div, pclk_div, sclk_div, sclk2x_div, root_div;
1342aa288248SMaxime Ripard 	u8 prediv, mult, sysdiv;
13436c957ed7SJacopo Mondi 	unsigned long link_freq;
13446c957ed7SJacopo Mondi 	unsigned long sysclk;
13456c957ed7SJacopo Mondi 	u8 pclk_period;
13466c957ed7SJacopo Mondi 	u32 sample_rate;
13476c957ed7SJacopo Mondi 	u32 num_lanes;
1348aa288248SMaxime Ripard 	int ret;
1349aa288248SMaxime Ripard 
13506c957ed7SJacopo Mondi 	/* Use the link freq computed at ov5640_update_pixel_rate() time. */
13516c957ed7SJacopo Mondi 	link_freq = sensor->current_link_freq;
13526c957ed7SJacopo Mondi 
1353aa288248SMaxime Ripard 	/*
13546c957ed7SJacopo Mondi 	 * - mipi_div - Additional divider for the MIPI lane clock.
13556c957ed7SJacopo Mondi 	 *
13566c957ed7SJacopo Mondi 	 * Higher link frequencies would make sysclk > 1GHz.
13576c957ed7SJacopo Mondi 	 * Keep the sysclk low and do not divide in the MIPI domain.
1358aa288248SMaxime Ripard 	 */
13596c957ed7SJacopo Mondi 	if (link_freq > OV5640_LINK_RATE_MAX)
13606c957ed7SJacopo Mondi 		mipi_div = 1;
1361aa288248SMaxime Ripard 	else
13626c957ed7SJacopo Mondi 		mipi_div = 2;
1363aa288248SMaxime Ripard 
13646c957ed7SJacopo Mondi 	sysclk = link_freq * mipi_div;
13656c957ed7SJacopo Mondi 	ov5640_calc_sys_clk(sensor, sysclk, &prediv, &mult, &sysdiv);
1366aa288248SMaxime Ripard 
13676c957ed7SJacopo Mondi 	/*
13686c957ed7SJacopo Mondi 	 * Adjust PLL parameters to maintain the MIPI_SCLK-to-PCLK ratio.
13696c957ed7SJacopo Mondi 	 *
13706c957ed7SJacopo Mondi 	 * - root_div = 2 (fixed)
13716c957ed7SJacopo Mondi 	 * - bit_div : MIPI 8-bit = 2; MIPI 10-bit = 2.5
13726c957ed7SJacopo Mondi 	 * - pclk_div = 1 (fixed)
13736c957ed7SJacopo Mondi 	 * - p_div  = (2 lanes ? mipi_div : 2 * mipi_div)
13746c957ed7SJacopo Mondi 	 *
13756c957ed7SJacopo Mondi 	 * This results in the following MIPI_SCLK depending on the number
13766c957ed7SJacopo Mondi 	 * of lanes:
13776c957ed7SJacopo Mondi 	 *
13786c957ed7SJacopo Mondi 	 * - 2 lanes: MIPI_SCLK = (4 or 5) * PCLK
13796c957ed7SJacopo Mondi 	 * - 1 lanes: MIPI_SCLK = (8 or 10) * PCLK
13806c957ed7SJacopo Mondi 	 */
13816c957ed7SJacopo Mondi 	root_div = OV5640_PLL_CTRL3_PLL_ROOT_DIV_2;
13826c957ed7SJacopo Mondi 	bit_div =  OV5640_PLL_CTRL0_MIPI_MODE_8BIT;
13836c957ed7SJacopo Mondi 	pclk_div = ilog2(OV5640_PCLK_ROOT_DIV);
1384aa288248SMaxime Ripard 
13856c957ed7SJacopo Mondi 	/*
13866c957ed7SJacopo Mondi 	 * Scaler clock:
13876c957ed7SJacopo Mondi 	 * - YUV: PCLK >= 2 * SCLK
13886c957ed7SJacopo Mondi 	 * - RAW or JPEG: PCLK >= SCLK
13896c957ed7SJacopo Mondi 	 * - sclk2x_div = sclk_div / 2
13906c957ed7SJacopo Mondi 	 */
13916c957ed7SJacopo Mondi 	sclk_div = ilog2(OV5640_SCLK_ROOT_DIV);
13926c957ed7SJacopo Mondi 	sclk2x_div = ilog2(OV5640_SCLK2X_ROOT_DIV);
13936c957ed7SJacopo Mondi 
13946c957ed7SJacopo Mondi 	/*
13956c957ed7SJacopo Mondi 	 * Set the pixel clock period expressed in ns with 1-bit decimal
13966c957ed7SJacopo Mondi 	 * (0x01=0.5ns).
13976c957ed7SJacopo Mondi 	 *
13986c957ed7SJacopo Mondi 	 * The register is very briefly documented. In the OV5645 datasheet it
13996c957ed7SJacopo Mondi 	 * is described as (2 * pclk period), and from testing it seems the
14006c957ed7SJacopo Mondi 	 * actual definition is 2 * 8-bit sample period.
14016c957ed7SJacopo Mondi 	 *
14026c957ed7SJacopo Mondi 	 * 2 * sample_period = (mipi_clk * 2 * num_lanes / bpp) * (bpp / 8) / 2
14036c957ed7SJacopo Mondi 	 */
14046c957ed7SJacopo Mondi 	num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes;
14056c957ed7SJacopo Mondi 	sample_rate = (link_freq * mipi_div * num_lanes * 2) / 16;
14066c957ed7SJacopo Mondi 	pclk_period = 2000000000UL / sample_rate;
14076c957ed7SJacopo Mondi 
14086c957ed7SJacopo Mondi 	/* Program the clock tree registers. */
14096c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0, 0x0f, bit_div);
14106c957ed7SJacopo Mondi 	if (ret)
14116c957ed7SJacopo Mondi 		return ret;
14126c957ed7SJacopo Mondi 
14136c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, 0xff,
14146c957ed7SJacopo Mondi 			     (sysdiv << 4) | mipi_div);
1415aa288248SMaxime Ripard 	if (ret)
1416aa288248SMaxime Ripard 		return ret;
1417aa288248SMaxime Ripard 
1418aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2, 0xff, mult);
1419aa288248SMaxime Ripard 	if (ret)
1420aa288248SMaxime Ripard 		return ret;
1421aa288248SMaxime Ripard 
14226c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3, 0x1f,
14236c957ed7SJacopo Mondi 			     root_div | prediv);
1424aa288248SMaxime Ripard 	if (ret)
1425aa288248SMaxime Ripard 		return ret;
1426aa288248SMaxime Ripard 
14276c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
14286c957ed7SJacopo Mondi 			     (pclk_div << 4) | (sclk2x_div << 2) | sclk_div);
14296c957ed7SJacopo Mondi 	if (ret)
14306c957ed7SJacopo Mondi 		return ret;
14316c957ed7SJacopo Mondi 
14326c957ed7SJacopo Mondi 	return ov5640_write_reg(sensor, OV5640_REG_PCLK_PERIOD, pclk_period);
14336c957ed7SJacopo Mondi }
14346c957ed7SJacopo Mondi 
14356c957ed7SJacopo Mondi static u32 ov5640_calc_pixel_rate(struct ov5640_dev *sensor)
14366c957ed7SJacopo Mondi {
14373145efcdSJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
14385113d5b3SJacopo Mondi 	const struct ov5640_timings *timings = &mode->dvp_timings;
14396c957ed7SJacopo Mondi 	u32 rate;
14406c957ed7SJacopo Mondi 
14415113d5b3SJacopo Mondi 	rate = timings->htot * (timings->crop.height + timings->vblank_def);
14426c957ed7SJacopo Mondi 	rate *= ov5640_framerates[sensor->current_fr];
14436c957ed7SJacopo Mondi 
14446c957ed7SJacopo Mondi 	return rate;
1445aa288248SMaxime Ripard }
1446aa288248SMaxime Ripard 
1447aa288248SMaxime Ripard static unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor,
1448aa288248SMaxime Ripard 				      unsigned long rate,
1449aa288248SMaxime Ripard 				      u8 *pll_prediv, u8 *pll_mult, u8 *sysdiv,
1450aa288248SMaxime Ripard 				      u8 *pll_rdiv, u8 *bit_div, u8 *pclk_div)
1451aa288248SMaxime Ripard {
1452aa288248SMaxime Ripard 	unsigned long _rate = rate * OV5640_PLL_ROOT_DIV * OV5640_BIT_DIV *
1453aa288248SMaxime Ripard 				OV5640_PCLK_ROOT_DIV;
1454aa288248SMaxime Ripard 
1455aa288248SMaxime Ripard 	_rate = ov5640_calc_sys_clk(sensor, _rate, pll_prediv, pll_mult,
1456aa288248SMaxime Ripard 				    sysdiv);
1457aa288248SMaxime Ripard 	*pll_rdiv = OV5640_PLL_ROOT_DIV;
1458aa288248SMaxime Ripard 	*bit_div = OV5640_BIT_DIV;
1459aa288248SMaxime Ripard 	*pclk_div = OV5640_PCLK_ROOT_DIV;
1460aa288248SMaxime Ripard 
1461aa288248SMaxime Ripard 	return _rate / *pll_rdiv / *bit_div / *pclk_div;
1462aa288248SMaxime Ripard }
1463aa288248SMaxime Ripard 
14646c957ed7SJacopo Mondi static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor)
1465aa288248SMaxime Ripard {
1466aa288248SMaxime Ripard 	u8 prediv, mult, sysdiv, pll_rdiv, bit_div, pclk_div;
14676c957ed7SJacopo Mondi 	u32 rate;
1468aa288248SMaxime Ripard 	int ret;
1469aa288248SMaxime Ripard 
14706c957ed7SJacopo Mondi 	rate = ov5640_calc_pixel_rate(sensor);
14716c957ed7SJacopo Mondi 	rate *= ov5640_code_to_bpp(sensor->fmt.code);
14726c957ed7SJacopo Mondi 	rate /= sensor->ep.bus.parallel.bus_width;
14736c957ed7SJacopo Mondi 
1474aa288248SMaxime Ripard 	ov5640_calc_pclk(sensor, rate, &prediv, &mult, &sysdiv, &pll_rdiv,
1475aa288248SMaxime Ripard 			 &bit_div, &pclk_div);
1476aa288248SMaxime Ripard 
1477aa288248SMaxime Ripard 	if (bit_div == 2)
1478aa288248SMaxime Ripard 		bit_div = 8;
1479aa288248SMaxime Ripard 
1480aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0,
1481aa288248SMaxime Ripard 			     0x0f, bit_div);
1482aa288248SMaxime Ripard 	if (ret)
1483aa288248SMaxime Ripard 		return ret;
1484aa288248SMaxime Ripard 
1485aa288248SMaxime Ripard 	/*
1486aa288248SMaxime Ripard 	 * We need to set sysdiv according to the clock, and to clear
1487aa288248SMaxime Ripard 	 * the MIPI divider.
1488aa288248SMaxime Ripard 	 */
1489aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1,
1490aa288248SMaxime Ripard 			     0xff, sysdiv << 4);
1491aa288248SMaxime Ripard 	if (ret)
1492aa288248SMaxime Ripard 		return ret;
1493aa288248SMaxime Ripard 
1494aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2,
1495aa288248SMaxime Ripard 			     0xff, mult);
1496aa288248SMaxime Ripard 	if (ret)
1497aa288248SMaxime Ripard 		return ret;
1498aa288248SMaxime Ripard 
1499aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3,
1500aa288248SMaxime Ripard 			     0x1f, prediv | ((pll_rdiv - 1) << 4));
1501aa288248SMaxime Ripard 	if (ret)
1502aa288248SMaxime Ripard 		return ret;
1503aa288248SMaxime Ripard 
1504aa288248SMaxime Ripard 	return ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x30,
1505aa288248SMaxime Ripard 			      (ilog2(pclk_div) << 4));
1506aa288248SMaxime Ripard }
1507aa288248SMaxime Ripard 
15087cb013b1SChen-Yu Tsai /* set JPEG framing sizes */
15097cb013b1SChen-Yu Tsai static int ov5640_set_jpeg_timings(struct ov5640_dev *sensor,
15107cb013b1SChen-Yu Tsai 				   const struct ov5640_mode_info *mode)
15117cb013b1SChen-Yu Tsai {
15127cb013b1SChen-Yu Tsai 	int ret;
15137cb013b1SChen-Yu Tsai 
15142b5c18f9SChen-Yu Tsai 	/*
15152b5c18f9SChen-Yu Tsai 	 * compression mode 3 timing
15162b5c18f9SChen-Yu Tsai 	 *
15172b5c18f9SChen-Yu Tsai 	 * Data is transmitted with programmable width (VFIFO_HSIZE).
15182b5c18f9SChen-Yu Tsai 	 * No padding done. Last line may have less data. Varying
15192b5c18f9SChen-Yu Tsai 	 * number of lines per frame, depending on amount of data.
15202b5c18f9SChen-Yu Tsai 	 */
15212b5c18f9SChen-Yu Tsai 	ret = ov5640_mod_reg(sensor, OV5640_REG_JPG_MODE_SELECT, 0x7, 0x3);
15222b5c18f9SChen-Yu Tsai 	if (ret < 0)
15232b5c18f9SChen-Yu Tsai 		return ret;
15242b5c18f9SChen-Yu Tsai 
15255113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_VFIFO_HSIZE, mode->width);
15267cb013b1SChen-Yu Tsai 	if (ret < 0)
15277cb013b1SChen-Yu Tsai 		return ret;
15287cb013b1SChen-Yu Tsai 
15295113d5b3SJacopo Mondi 	return ov5640_write_reg16(sensor, OV5640_REG_VFIFO_VSIZE, mode->height);
15307cb013b1SChen-Yu Tsai }
15317cb013b1SChen-Yu Tsai 
153219a81c14SSteve Longerbeam /* download ov5640 settings to sensor through i2c */
1533bad1774eSJacopo Mondi static int ov5640_set_timings(struct ov5640_dev *sensor,
1534bad1774eSJacopo Mondi 			      const struct ov5640_mode_info *mode)
1535bad1774eSJacopo Mondi {
15365113d5b3SJacopo Mondi 	const struct ov5640_timings *timings;
15375113d5b3SJacopo Mondi 	const struct v4l2_rect *analog_crop;
15385113d5b3SJacopo Mondi 	const struct v4l2_rect *crop;
1539bad1774eSJacopo Mondi 	int ret;
1540bad1774eSJacopo Mondi 
15417cb013b1SChen-Yu Tsai 	if (sensor->fmt.code == MEDIA_BUS_FMT_JPEG_1X8) {
15427cb013b1SChen-Yu Tsai 		ret = ov5640_set_jpeg_timings(sensor, mode);
15437cb013b1SChen-Yu Tsai 		if (ret < 0)
15447cb013b1SChen-Yu Tsai 			return ret;
15457cb013b1SChen-Yu Tsai 	}
15467cb013b1SChen-Yu Tsai 
15472de6bb97SJacopo Mondi 	timings = ov5640_timings(sensor, mode);
15485113d5b3SJacopo Mondi 	analog_crop = &timings->analog_crop;
15495113d5b3SJacopo Mondi 	crop = &timings->crop;
15505113d5b3SJacopo Mondi 
15513145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HS,
15523145efcdSJacopo Mondi 				 analog_crop->left);
1553bad1774eSJacopo Mondi 	if (ret < 0)
1554bad1774eSJacopo Mondi 		return ret;
1555bad1774eSJacopo Mondi 
15563145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VS,
15573145efcdSJacopo Mondi 				 analog_crop->top);
15583145efcdSJacopo Mondi 	if (ret < 0)
15593145efcdSJacopo Mondi 		return ret;
15603145efcdSJacopo Mondi 
15613145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HW,
15623145efcdSJacopo Mondi 				 analog_crop->left + analog_crop->width - 1);
15633145efcdSJacopo Mondi 	if (ret < 0)
15643145efcdSJacopo Mondi 		return ret;
15653145efcdSJacopo Mondi 
15663145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VH,
15673145efcdSJacopo Mondi 				 analog_crop->top + analog_crop->height - 1);
15683145efcdSJacopo Mondi 	if (ret < 0)
15693145efcdSJacopo Mondi 		return ret;
15703145efcdSJacopo Mondi 
15713145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HOFFS, crop->left);
15723145efcdSJacopo Mondi 	if (ret < 0)
15733145efcdSJacopo Mondi 		return ret;
15743145efcdSJacopo Mondi 
15753145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VOFFS, crop->top);
15763145efcdSJacopo Mondi 	if (ret < 0)
15773145efcdSJacopo Mondi 		return ret;
15783145efcdSJacopo Mondi 
15795113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->width);
15803145efcdSJacopo Mondi 	if (ret < 0)
15813145efcdSJacopo Mondi 		return ret;
15823145efcdSJacopo Mondi 
15835113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, mode->height);
1584bad1774eSJacopo Mondi 	if (ret < 0)
1585bad1774eSJacopo Mondi 		return ret;
1586bad1774eSJacopo Mondi 
15875113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, timings->htot);
1588bad1774eSJacopo Mondi 	if (ret < 0)
1589bad1774eSJacopo Mondi 		return ret;
1590bad1774eSJacopo Mondi 
15913145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS,
15925113d5b3SJacopo Mondi 				 mode->height + timings->vblank_def);
15933145efcdSJacopo Mondi 	if (ret < 0)
15943145efcdSJacopo Mondi 		return ret;
15953145efcdSJacopo Mondi 
15963145efcdSJacopo Mondi 	return 0;
1597bad1774eSJacopo Mondi }
1598bad1774eSJacopo Mondi 
1599e4359019SJacopo Mondi static void ov5640_load_regs(struct ov5640_dev *sensor,
1600e4359019SJacopo Mondi 			     const struct reg_value *regs, unsigned int regnum)
160119a81c14SSteve Longerbeam {
160219a81c14SSteve Longerbeam 	unsigned int i;
160319a81c14SSteve Longerbeam 	u32 delay_ms;
160419a81c14SSteve Longerbeam 	u16 reg_addr;
160519a81c14SSteve Longerbeam 	u8 mask, val;
160619a81c14SSteve Longerbeam 	int ret = 0;
160719a81c14SSteve Longerbeam 
1608e4359019SJacopo Mondi 	for (i = 0; i < regnum; ++i, ++regs) {
160919a81c14SSteve Longerbeam 		delay_ms = regs->delay_ms;
161019a81c14SSteve Longerbeam 		reg_addr = regs->reg_addr;
161119a81c14SSteve Longerbeam 		val = regs->val;
161219a81c14SSteve Longerbeam 		mask = regs->mask;
161319a81c14SSteve Longerbeam 
16143b987d70SLad Prabhakar 		/* remain in power down mode for DVP */
16153b987d70SLad Prabhakar 		if (regs->reg_addr == OV5640_REG_SYS_CTRL0 &&
16163b987d70SLad Prabhakar 		    val == OV5640_REG_SYS_CTRL0_SW_PWUP &&
16178e823f5cSJacopo Mondi 		    !ov5640_is_csi2(sensor))
16183b987d70SLad Prabhakar 			continue;
16193b987d70SLad Prabhakar 
162019a81c14SSteve Longerbeam 		if (mask)
162119a81c14SSteve Longerbeam 			ret = ov5640_mod_reg(sensor, reg_addr, mask, val);
162219a81c14SSteve Longerbeam 		else
162319a81c14SSteve Longerbeam 			ret = ov5640_write_reg(sensor, reg_addr, val);
162419a81c14SSteve Longerbeam 		if (ret)
162519a81c14SSteve Longerbeam 			break;
162619a81c14SSteve Longerbeam 
162719a81c14SSteve Longerbeam 		if (delay_ms)
162819a81c14SSteve Longerbeam 			usleep_range(1000 * delay_ms, 1000 * delay_ms + 100);
162919a81c14SSteve Longerbeam 	}
163019a81c14SSteve Longerbeam }
163119a81c14SSteve Longerbeam 
1632dc29a1c1SHugues Fruchet static int ov5640_set_autoexposure(struct ov5640_dev *sensor, bool on)
1633dc29a1c1SHugues Fruchet {
1634dc29a1c1SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
1635dc29a1c1SHugues Fruchet 			      BIT(0), on ? 0 : BIT(0));
1636dc29a1c1SHugues Fruchet }
1637dc29a1c1SHugues Fruchet 
163819a81c14SSteve Longerbeam /* read exposure, in number of line periods */
163919a81c14SSteve Longerbeam static int ov5640_get_exposure(struct ov5640_dev *sensor)
164019a81c14SSteve Longerbeam {
164119a81c14SSteve Longerbeam 	int exp, ret;
164219a81c14SSteve Longerbeam 	u8 temp;
164319a81c14SSteve Longerbeam 
164419a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_HI, &temp);
164519a81c14SSteve Longerbeam 	if (ret)
164619a81c14SSteve Longerbeam 		return ret;
164719a81c14SSteve Longerbeam 	exp = ((int)temp & 0x0f) << 16;
164819a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_MED, &temp);
164919a81c14SSteve Longerbeam 	if (ret)
165019a81c14SSteve Longerbeam 		return ret;
165119a81c14SSteve Longerbeam 	exp |= ((int)temp << 8);
165219a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_LO, &temp);
165319a81c14SSteve Longerbeam 	if (ret)
165419a81c14SSteve Longerbeam 		return ret;
165519a81c14SSteve Longerbeam 	exp |= (int)temp;
165619a81c14SSteve Longerbeam 
165719a81c14SSteve Longerbeam 	return exp >> 4;
165819a81c14SSteve Longerbeam }
165919a81c14SSteve Longerbeam 
166019a81c14SSteve Longerbeam /* write exposure, given number of line periods */
166119a81c14SSteve Longerbeam static int ov5640_set_exposure(struct ov5640_dev *sensor, u32 exposure)
166219a81c14SSteve Longerbeam {
166319a81c14SSteve Longerbeam 	int ret;
166419a81c14SSteve Longerbeam 
166519a81c14SSteve Longerbeam 	exposure <<= 4;
166619a81c14SSteve Longerbeam 
166719a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor,
166819a81c14SSteve Longerbeam 			       OV5640_REG_AEC_PK_EXPOSURE_LO,
166919a81c14SSteve Longerbeam 			       exposure & 0xff);
167019a81c14SSteve Longerbeam 	if (ret)
167119a81c14SSteve Longerbeam 		return ret;
167219a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor,
167319a81c14SSteve Longerbeam 			       OV5640_REG_AEC_PK_EXPOSURE_MED,
167419a81c14SSteve Longerbeam 			       (exposure >> 8) & 0xff);
167519a81c14SSteve Longerbeam 	if (ret)
167619a81c14SSteve Longerbeam 		return ret;
167719a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor,
167819a81c14SSteve Longerbeam 				OV5640_REG_AEC_PK_EXPOSURE_HI,
167919a81c14SSteve Longerbeam 				(exposure >> 16) & 0x0f);
168019a81c14SSteve Longerbeam }
168119a81c14SSteve Longerbeam 
168219a81c14SSteve Longerbeam static int ov5640_get_gain(struct ov5640_dev *sensor)
168319a81c14SSteve Longerbeam {
168419a81c14SSteve Longerbeam 	u16 gain;
168519a81c14SSteve Longerbeam 	int ret;
168619a81c14SSteve Longerbeam 
168719a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN, &gain);
168819a81c14SSteve Longerbeam 	if (ret)
168919a81c14SSteve Longerbeam 		return ret;
169019a81c14SSteve Longerbeam 
169119a81c14SSteve Longerbeam 	return gain & 0x3ff;
169219a81c14SSteve Longerbeam }
169319a81c14SSteve Longerbeam 
16943cca8ef5SHugues Fruchet static int ov5640_set_gain(struct ov5640_dev *sensor, int gain)
16953cca8ef5SHugues Fruchet {
16963cca8ef5SHugues Fruchet 	return ov5640_write_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN,
16973cca8ef5SHugues Fruchet 				  (u16)gain & 0x3ff);
16983cca8ef5SHugues Fruchet }
16993cca8ef5SHugues Fruchet 
17003cca8ef5SHugues Fruchet static int ov5640_set_autogain(struct ov5640_dev *sensor, bool on)
17013cca8ef5SHugues Fruchet {
17023cca8ef5SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
17033cca8ef5SHugues Fruchet 			      BIT(1), on ? 0 : BIT(1));
17043cca8ef5SHugues Fruchet }
17053cca8ef5SHugues Fruchet 
1706f22996dbSHugues Fruchet static int ov5640_set_stream_dvp(struct ov5640_dev *sensor, bool on)
1707f22996dbSHugues Fruchet {
17083b987d70SLad Prabhakar 	return ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0, on ?
17093b987d70SLad Prabhakar 				OV5640_REG_SYS_CTRL0_SW_PWUP :
17103b987d70SLad Prabhakar 				OV5640_REG_SYS_CTRL0_SW_PWDN);
1711f22996dbSHugues Fruchet }
1712f22996dbSHugues Fruchet 
1713f22996dbSHugues Fruchet static int ov5640_set_stream_mipi(struct ov5640_dev *sensor, bool on)
171419a81c14SSteve Longerbeam {
171519a81c14SSteve Longerbeam 	int ret;
171619a81c14SSteve Longerbeam 
1717aa4bb8b8SJacopo Mondi 	/*
1718aa4bb8b8SJacopo Mondi 	 * Enable/disable the MIPI interface
1719aa4bb8b8SJacopo Mondi 	 *
1720aa4bb8b8SJacopo Mondi 	 * 0x300e = on ? 0x45 : 0x40
1721aa4bb8b8SJacopo Mondi 	 *
1722aa4bb8b8SJacopo Mondi 	 * FIXME: the sensor manual (version 2.03) reports
1723aa4bb8b8SJacopo Mondi 	 * [7:5] = 000  : 1 data lane mode
1724aa4bb8b8SJacopo Mondi 	 * [7:5] = 001  : 2 data lanes mode
1725aa4bb8b8SJacopo Mondi 	 * But this settings do not work, while the following ones
1726aa4bb8b8SJacopo Mondi 	 * have been validated for 2 data lanes mode.
1727aa4bb8b8SJacopo Mondi 	 *
1728aa4bb8b8SJacopo Mondi 	 * [7:5] = 010	: 2 data lanes mode
1729aa4bb8b8SJacopo Mondi 	 * [4] = 0	: Power up MIPI HS Tx
1730aa4bb8b8SJacopo Mondi 	 * [3] = 0	: Power up MIPI LS Rx
1731aa4bb8b8SJacopo Mondi 	 * [2] = 1/0	: MIPI interface enable/disable
1732aa4bb8b8SJacopo Mondi 	 * [1:0] = 01/00: FIXME: 'debug'
1733aa4bb8b8SJacopo Mondi 	 */
1734aa4bb8b8SJacopo Mondi 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00,
1735aa4bb8b8SJacopo Mondi 			       on ? 0x45 : 0x40);
173619a81c14SSteve Longerbeam 	if (ret)
173719a81c14SSteve Longerbeam 		return ret;
173819a81c14SSteve Longerbeam 
173919a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_FRAME_CTRL01,
174019a81c14SSteve Longerbeam 				on ? 0x00 : 0x0f);
174119a81c14SSteve Longerbeam }
174219a81c14SSteve Longerbeam 
174319a81c14SSteve Longerbeam static int ov5640_get_sysclk(struct ov5640_dev *sensor)
174419a81c14SSteve Longerbeam {
174519a81c14SSteve Longerbeam 	 /* calculate sysclk */
174619a81c14SSteve Longerbeam 	u32 xvclk = sensor->xclk_freq / 10000;
174719a81c14SSteve Longerbeam 	u32 multiplier, prediv, VCO, sysdiv, pll_rdiv;
174819a81c14SSteve Longerbeam 	u32 sclk_rdiv_map[] = {1, 2, 4, 8};
174919a81c14SSteve Longerbeam 	u32 bit_div2x = 1, sclk_rdiv, sysclk;
175019a81c14SSteve Longerbeam 	u8 temp1, temp2;
175119a81c14SSteve Longerbeam 	int ret;
175219a81c14SSteve Longerbeam 
175319a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL0, &temp1);
175419a81c14SSteve Longerbeam 	if (ret)
175519a81c14SSteve Longerbeam 		return ret;
175619a81c14SSteve Longerbeam 	temp2 = temp1 & 0x0f;
175719a81c14SSteve Longerbeam 	if (temp2 == 8 || temp2 == 10)
175819a81c14SSteve Longerbeam 		bit_div2x = temp2 / 2;
175919a81c14SSteve Longerbeam 
176019a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL1, &temp1);
176119a81c14SSteve Longerbeam 	if (ret)
176219a81c14SSteve Longerbeam 		return ret;
176319a81c14SSteve Longerbeam 	sysdiv = temp1 >> 4;
176419a81c14SSteve Longerbeam 	if (sysdiv == 0)
176519a81c14SSteve Longerbeam 		sysdiv = 16;
176619a81c14SSteve Longerbeam 
176719a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL2, &temp1);
176819a81c14SSteve Longerbeam 	if (ret)
176919a81c14SSteve Longerbeam 		return ret;
177019a81c14SSteve Longerbeam 	multiplier = temp1;
177119a81c14SSteve Longerbeam 
177219a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL3, &temp1);
177319a81c14SSteve Longerbeam 	if (ret)
177419a81c14SSteve Longerbeam 		return ret;
177519a81c14SSteve Longerbeam 	prediv = temp1 & 0x0f;
177619a81c14SSteve Longerbeam 	pll_rdiv = ((temp1 >> 4) & 0x01) + 1;
177719a81c14SSteve Longerbeam 
177819a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, &temp1);
177919a81c14SSteve Longerbeam 	if (ret)
178019a81c14SSteve Longerbeam 		return ret;
178119a81c14SSteve Longerbeam 	temp2 = temp1 & 0x03;
178219a81c14SSteve Longerbeam 	sclk_rdiv = sclk_rdiv_map[temp2];
178319a81c14SSteve Longerbeam 
178419a81c14SSteve Longerbeam 	if (!prediv || !sysdiv || !pll_rdiv || !bit_div2x)
178519a81c14SSteve Longerbeam 		return -EINVAL;
178619a81c14SSteve Longerbeam 
178719a81c14SSteve Longerbeam 	VCO = xvclk * multiplier / prediv;
178819a81c14SSteve Longerbeam 
178919a81c14SSteve Longerbeam 	sysclk = VCO / sysdiv / pll_rdiv * 2 / bit_div2x / sclk_rdiv;
179019a81c14SSteve Longerbeam 
179119a81c14SSteve Longerbeam 	return sysclk;
179219a81c14SSteve Longerbeam }
179319a81c14SSteve Longerbeam 
179419a81c14SSteve Longerbeam static int ov5640_set_night_mode(struct ov5640_dev *sensor)
179519a81c14SSteve Longerbeam {
179619a81c14SSteve Longerbeam 	 /* read HTS from register settings */
179719a81c14SSteve Longerbeam 	u8 mode;
179819a81c14SSteve Longerbeam 	int ret;
179919a81c14SSteve Longerbeam 
180019a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_CTRL00, &mode);
180119a81c14SSteve Longerbeam 	if (ret)
180219a81c14SSteve Longerbeam 		return ret;
180319a81c14SSteve Longerbeam 	mode &= 0xfb;
180419a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL00, mode);
180519a81c14SSteve Longerbeam }
180619a81c14SSteve Longerbeam 
180719a81c14SSteve Longerbeam static int ov5640_get_hts(struct ov5640_dev *sensor)
180819a81c14SSteve Longerbeam {
180919a81c14SSteve Longerbeam 	/* read HTS from register settings */
181019a81c14SSteve Longerbeam 	u16 hts;
181119a81c14SSteve Longerbeam 	int ret;
181219a81c14SSteve Longerbeam 
181319a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_HTS, &hts);
181419a81c14SSteve Longerbeam 	if (ret)
181519a81c14SSteve Longerbeam 		return ret;
181619a81c14SSteve Longerbeam 	return hts;
181719a81c14SSteve Longerbeam }
181819a81c14SSteve Longerbeam 
181919a81c14SSteve Longerbeam static int ov5640_get_vts(struct ov5640_dev *sensor)
182019a81c14SSteve Longerbeam {
182119a81c14SSteve Longerbeam 	u16 vts;
182219a81c14SSteve Longerbeam 	int ret;
182319a81c14SSteve Longerbeam 
182419a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_VTS, &vts);
182519a81c14SSteve Longerbeam 	if (ret)
182619a81c14SSteve Longerbeam 		return ret;
182719a81c14SSteve Longerbeam 	return vts;
182819a81c14SSteve Longerbeam }
182919a81c14SSteve Longerbeam 
183019a81c14SSteve Longerbeam static int ov5640_set_vts(struct ov5640_dev *sensor, int vts)
183119a81c14SSteve Longerbeam {
183219a81c14SSteve Longerbeam 	return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, vts);
183319a81c14SSteve Longerbeam }
183419a81c14SSteve Longerbeam 
183519a81c14SSteve Longerbeam static int ov5640_get_light_freq(struct ov5640_dev *sensor)
183619a81c14SSteve Longerbeam {
183719a81c14SSteve Longerbeam 	/* get banding filter value */
183819a81c14SSteve Longerbeam 	int ret, light_freq = 0;
183919a81c14SSteve Longerbeam 	u8 temp, temp1;
184019a81c14SSteve Longerbeam 
184119a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL01, &temp);
184219a81c14SSteve Longerbeam 	if (ret)
184319a81c14SSteve Longerbeam 		return ret;
184419a81c14SSteve Longerbeam 
184519a81c14SSteve Longerbeam 	if (temp & 0x80) {
184619a81c14SSteve Longerbeam 		/* manual */
184719a81c14SSteve Longerbeam 		ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL00,
184819a81c14SSteve Longerbeam 				      &temp1);
184919a81c14SSteve Longerbeam 		if (ret)
185019a81c14SSteve Longerbeam 			return ret;
185119a81c14SSteve Longerbeam 		if (temp1 & 0x04) {
185219a81c14SSteve Longerbeam 			/* 50Hz */
185319a81c14SSteve Longerbeam 			light_freq = 50;
185419a81c14SSteve Longerbeam 		} else {
185519a81c14SSteve Longerbeam 			/* 60Hz */
185619a81c14SSteve Longerbeam 			light_freq = 60;
185719a81c14SSteve Longerbeam 		}
185819a81c14SSteve Longerbeam 	} else {
185919a81c14SSteve Longerbeam 		/* auto */
186019a81c14SSteve Longerbeam 		ret = ov5640_read_reg(sensor, OV5640_REG_SIGMADELTA_CTRL0C,
186119a81c14SSteve Longerbeam 				      &temp1);
186219a81c14SSteve Longerbeam 		if (ret)
186319a81c14SSteve Longerbeam 			return ret;
186419a81c14SSteve Longerbeam 
186519a81c14SSteve Longerbeam 		if (temp1 & 0x01) {
186619a81c14SSteve Longerbeam 			/* 50Hz */
186719a81c14SSteve Longerbeam 			light_freq = 50;
186819a81c14SSteve Longerbeam 		} else {
186919a81c14SSteve Longerbeam 			/* 60Hz */
187019a81c14SSteve Longerbeam 		}
187119a81c14SSteve Longerbeam 	}
187219a81c14SSteve Longerbeam 
187319a81c14SSteve Longerbeam 	return light_freq;
187419a81c14SSteve Longerbeam }
187519a81c14SSteve Longerbeam 
187619a81c14SSteve Longerbeam static int ov5640_set_bandingfilter(struct ov5640_dev *sensor)
187719a81c14SSteve Longerbeam {
187819a81c14SSteve Longerbeam 	u32 band_step60, max_band60, band_step50, max_band50, prev_vts;
187919a81c14SSteve Longerbeam 	int ret;
188019a81c14SSteve Longerbeam 
188119a81c14SSteve Longerbeam 	/* read preview PCLK */
188219a81c14SSteve Longerbeam 	ret = ov5640_get_sysclk(sensor);
188319a81c14SSteve Longerbeam 	if (ret < 0)
188419a81c14SSteve Longerbeam 		return ret;
188519a81c14SSteve Longerbeam 	if (ret == 0)
188619a81c14SSteve Longerbeam 		return -EINVAL;
188719a81c14SSteve Longerbeam 	sensor->prev_sysclk = ret;
188819a81c14SSteve Longerbeam 	/* read preview HTS */
188919a81c14SSteve Longerbeam 	ret = ov5640_get_hts(sensor);
189019a81c14SSteve Longerbeam 	if (ret < 0)
189119a81c14SSteve Longerbeam 		return ret;
189219a81c14SSteve Longerbeam 	if (ret == 0)
189319a81c14SSteve Longerbeam 		return -EINVAL;
189419a81c14SSteve Longerbeam 	sensor->prev_hts = ret;
189519a81c14SSteve Longerbeam 
189619a81c14SSteve Longerbeam 	/* read preview VTS */
189719a81c14SSteve Longerbeam 	ret = ov5640_get_vts(sensor);
189819a81c14SSteve Longerbeam 	if (ret < 0)
189919a81c14SSteve Longerbeam 		return ret;
190019a81c14SSteve Longerbeam 	prev_vts = ret;
190119a81c14SSteve Longerbeam 
190219a81c14SSteve Longerbeam 	/* calculate banding filter */
190319a81c14SSteve Longerbeam 	/* 60Hz */
190419a81c14SSteve Longerbeam 	band_step60 = sensor->prev_sysclk * 100 / sensor->prev_hts * 100 / 120;
190519a81c14SSteve Longerbeam 	ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B60_STEP, band_step60);
190619a81c14SSteve Longerbeam 	if (ret)
190719a81c14SSteve Longerbeam 		return ret;
190819a81c14SSteve Longerbeam 	if (!band_step60)
190919a81c14SSteve Longerbeam 		return -EINVAL;
191019a81c14SSteve Longerbeam 	max_band60 = (int)((prev_vts - 4) / band_step60);
191119a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0D, max_band60);
191219a81c14SSteve Longerbeam 	if (ret)
191319a81c14SSteve Longerbeam 		return ret;
191419a81c14SSteve Longerbeam 
191519a81c14SSteve Longerbeam 	/* 50Hz */
191619a81c14SSteve Longerbeam 	band_step50 = sensor->prev_sysclk * 100 / sensor->prev_hts;
191719a81c14SSteve Longerbeam 	ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B50_STEP, band_step50);
191819a81c14SSteve Longerbeam 	if (ret)
191919a81c14SSteve Longerbeam 		return ret;
192019a81c14SSteve Longerbeam 	if (!band_step50)
192119a81c14SSteve Longerbeam 		return -EINVAL;
192219a81c14SSteve Longerbeam 	max_band50 = (int)((prev_vts - 4) / band_step50);
192319a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0E, max_band50);
192419a81c14SSteve Longerbeam }
192519a81c14SSteve Longerbeam 
192619a81c14SSteve Longerbeam static int ov5640_set_ae_target(struct ov5640_dev *sensor, int target)
192719a81c14SSteve Longerbeam {
192819a81c14SSteve Longerbeam 	/* stable in high */
192919a81c14SSteve Longerbeam 	u32 fast_high, fast_low;
193019a81c14SSteve Longerbeam 	int ret;
193119a81c14SSteve Longerbeam 
193219a81c14SSteve Longerbeam 	sensor->ae_low = target * 23 / 25;	/* 0.92 */
193319a81c14SSteve Longerbeam 	sensor->ae_high = target * 27 / 25;	/* 1.08 */
193419a81c14SSteve Longerbeam 
193519a81c14SSteve Longerbeam 	fast_high = sensor->ae_high << 1;
193619a81c14SSteve Longerbeam 	if (fast_high > 255)
193719a81c14SSteve Longerbeam 		fast_high = 255;
193819a81c14SSteve Longerbeam 
193919a81c14SSteve Longerbeam 	fast_low = sensor->ae_low >> 1;
194019a81c14SSteve Longerbeam 
194119a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0F, sensor->ae_high);
194219a81c14SSteve Longerbeam 	if (ret)
194319a81c14SSteve Longerbeam 		return ret;
194419a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL10, sensor->ae_low);
194519a81c14SSteve Longerbeam 	if (ret)
194619a81c14SSteve Longerbeam 		return ret;
194719a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1B, sensor->ae_high);
194819a81c14SSteve Longerbeam 	if (ret)
194919a81c14SSteve Longerbeam 		return ret;
195019a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1E, sensor->ae_low);
195119a81c14SSteve Longerbeam 	if (ret)
195219a81c14SSteve Longerbeam 		return ret;
195319a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL11, fast_high);
195419a81c14SSteve Longerbeam 	if (ret)
195519a81c14SSteve Longerbeam 		return ret;
195619a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1F, fast_low);
195719a81c14SSteve Longerbeam }
195819a81c14SSteve Longerbeam 
1959c2c3f42dSHugues Fruchet static int ov5640_get_binning(struct ov5640_dev *sensor)
196019a81c14SSteve Longerbeam {
196119a81c14SSteve Longerbeam 	u8 temp;
196219a81c14SSteve Longerbeam 	int ret;
196319a81c14SSteve Longerbeam 
196419a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_TIMING_TC_REG21, &temp);
196519a81c14SSteve Longerbeam 	if (ret)
196619a81c14SSteve Longerbeam 		return ret;
1967c2c3f42dSHugues Fruchet 
1968c2c3f42dSHugues Fruchet 	return temp & BIT(0);
196919a81c14SSteve Longerbeam }
197019a81c14SSteve Longerbeam 
1971ce85705aSHugues Fruchet static int ov5640_set_binning(struct ov5640_dev *sensor, bool enable)
1972ce85705aSHugues Fruchet {
1973ce85705aSHugues Fruchet 	int ret;
1974ce85705aSHugues Fruchet 
1975ce85705aSHugues Fruchet 	/*
1976ce85705aSHugues Fruchet 	 * TIMING TC REG21:
1977ce85705aSHugues Fruchet 	 * - [0]:	Horizontal binning enable
1978ce85705aSHugues Fruchet 	 */
1979ce85705aSHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
1980ce85705aSHugues Fruchet 			     BIT(0), enable ? BIT(0) : 0);
1981ce85705aSHugues Fruchet 	if (ret)
1982ce85705aSHugues Fruchet 		return ret;
1983ce85705aSHugues Fruchet 	/*
1984ce85705aSHugues Fruchet 	 * TIMING TC REG20:
1985ce85705aSHugues Fruchet 	 * - [0]:	Undocumented, but hardcoded init sequences
1986ce85705aSHugues Fruchet 	 *		are always setting REG21/REG20 bit 0 to same value...
1987ce85705aSHugues Fruchet 	 */
1988ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20,
1989ce85705aSHugues Fruchet 			      BIT(0), enable ? BIT(0) : 0);
1990ce85705aSHugues Fruchet }
1991ce85705aSHugues Fruchet 
199219a81c14SSteve Longerbeam static int ov5640_set_virtual_channel(struct ov5640_dev *sensor)
199319a81c14SSteve Longerbeam {
19948670d70aSHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
199519a81c14SSteve Longerbeam 	u8 temp, channel = virtual_channel;
199619a81c14SSteve Longerbeam 	int ret;
199719a81c14SSteve Longerbeam 
19988670d70aSHugues Fruchet 	if (channel > 3) {
19998670d70aSHugues Fruchet 		dev_err(&client->dev,
20008670d70aSHugues Fruchet 			"%s: wrong virtual_channel parameter, expected (0..3), got %d\n",
20018670d70aSHugues Fruchet 			__func__, channel);
200219a81c14SSteve Longerbeam 		return -EINVAL;
20038670d70aSHugues Fruchet 	}
200419a81c14SSteve Longerbeam 
200519a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_DEBUG_MODE, &temp);
200619a81c14SSteve Longerbeam 	if (ret)
200719a81c14SSteve Longerbeam 		return ret;
200819a81c14SSteve Longerbeam 	temp &= ~(3 << 6);
200919a81c14SSteve Longerbeam 	temp |= (channel << 6);
201019a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_DEBUG_MODE, temp);
201119a81c14SSteve Longerbeam }
201219a81c14SSteve Longerbeam 
201319a81c14SSteve Longerbeam static const struct ov5640_mode_info *
2014b6ae5022SJacopo Mondi ov5640_find_mode(struct ov5640_dev *sensor, int width, int height, bool nearest)
201519a81c14SSteve Longerbeam {
20163c4a7372SHugues Fruchet 	const struct ov5640_mode_info *mode;
201719a81c14SSteve Longerbeam 
2018086c25f8SMaxime Ripard 	mode = v4l2_find_nearest_size(ov5640_mode_data,
2019086c25f8SMaxime Ripard 				      ARRAY_SIZE(ov5640_mode_data),
20205113d5b3SJacopo Mondi 				      width, height, width, height);
202119a81c14SSteve Longerbeam 
20223c4a7372SHugues Fruchet 	if (!mode ||
20233145efcdSJacopo Mondi 	    (!nearest &&
20245113d5b3SJacopo Mondi 	     (mode->width != width || mode->height != height)))
20253c4a7372SHugues Fruchet 		return NULL;
202619a81c14SSteve Longerbeam 
202719a81c14SSteve Longerbeam 	return mode;
202819a81c14SSteve Longerbeam }
202919a81c14SSteve Longerbeam 
203019a81c14SSteve Longerbeam /*
203119a81c14SSteve Longerbeam  * sensor changes between scaling and subsampling, go through
203219a81c14SSteve Longerbeam  * exposure calculation
203319a81c14SSteve Longerbeam  */
203441d8d7f5SHugues Fruchet static int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor,
203541d8d7f5SHugues Fruchet 					 const struct ov5640_mode_info *mode)
203619a81c14SSteve Longerbeam {
203719a81c14SSteve Longerbeam 	u32 prev_shutter, prev_gain16;
203819a81c14SSteve Longerbeam 	u32 cap_shutter, cap_gain16;
203919a81c14SSteve Longerbeam 	u32 cap_sysclk, cap_hts, cap_vts;
204019a81c14SSteve Longerbeam 	u32 light_freq, cap_bandfilt, cap_maxband;
204119a81c14SSteve Longerbeam 	u32 cap_gain16_shutter;
204219a81c14SSteve Longerbeam 	u8 average;
204319a81c14SSteve Longerbeam 	int ret;
204419a81c14SSteve Longerbeam 
204541d8d7f5SHugues Fruchet 	if (!mode->reg_data)
204619a81c14SSteve Longerbeam 		return -EINVAL;
204719a81c14SSteve Longerbeam 
204819a81c14SSteve Longerbeam 	/* read preview shutter */
204919a81c14SSteve Longerbeam 	ret = ov5640_get_exposure(sensor);
205019a81c14SSteve Longerbeam 	if (ret < 0)
205119a81c14SSteve Longerbeam 		return ret;
205219a81c14SSteve Longerbeam 	prev_shutter = ret;
2053c2c3f42dSHugues Fruchet 	ret = ov5640_get_binning(sensor);
205419a81c14SSteve Longerbeam 	if (ret < 0)
205519a81c14SSteve Longerbeam 		return ret;
205619a81c14SSteve Longerbeam 	if (ret && mode->id != OV5640_MODE_720P_1280_720 &&
205719a81c14SSteve Longerbeam 	    mode->id != OV5640_MODE_1080P_1920_1080)
205819a81c14SSteve Longerbeam 		prev_shutter *= 2;
205919a81c14SSteve Longerbeam 
206019a81c14SSteve Longerbeam 	/* read preview gain */
206119a81c14SSteve Longerbeam 	ret = ov5640_get_gain(sensor);
206219a81c14SSteve Longerbeam 	if (ret < 0)
206319a81c14SSteve Longerbeam 		return ret;
206419a81c14SSteve Longerbeam 	prev_gain16 = ret;
206519a81c14SSteve Longerbeam 
206619a81c14SSteve Longerbeam 	/* get average */
206719a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AVG_READOUT, &average);
206819a81c14SSteve Longerbeam 	if (ret)
206919a81c14SSteve Longerbeam 		return ret;
207019a81c14SSteve Longerbeam 
207119a81c14SSteve Longerbeam 	/* turn off night mode for capture */
207219a81c14SSteve Longerbeam 	ret = ov5640_set_night_mode(sensor);
207319a81c14SSteve Longerbeam 	if (ret < 0)
207419a81c14SSteve Longerbeam 		return ret;
207519a81c14SSteve Longerbeam 
207619a81c14SSteve Longerbeam 	/* Write capture setting */
2077e4359019SJacopo Mondi 	ov5640_load_regs(sensor, mode->reg_data, mode->reg_data_size);
2078e4359019SJacopo Mondi 	ret = ov5640_set_timings(sensor, mode);
207919a81c14SSteve Longerbeam 	if (ret < 0)
208019a81c14SSteve Longerbeam 		return ret;
208119a81c14SSteve Longerbeam 
208219a81c14SSteve Longerbeam 	/* read capture VTS */
208319a81c14SSteve Longerbeam 	ret = ov5640_get_vts(sensor);
208419a81c14SSteve Longerbeam 	if (ret < 0)
208519a81c14SSteve Longerbeam 		return ret;
208619a81c14SSteve Longerbeam 	cap_vts = ret;
208719a81c14SSteve Longerbeam 	ret = ov5640_get_hts(sensor);
208819a81c14SSteve Longerbeam 	if (ret < 0)
208919a81c14SSteve Longerbeam 		return ret;
209019a81c14SSteve Longerbeam 	if (ret == 0)
209119a81c14SSteve Longerbeam 		return -EINVAL;
209219a81c14SSteve Longerbeam 	cap_hts = ret;
209319a81c14SSteve Longerbeam 
209419a81c14SSteve Longerbeam 	ret = ov5640_get_sysclk(sensor);
209519a81c14SSteve Longerbeam 	if (ret < 0)
209619a81c14SSteve Longerbeam 		return ret;
209719a81c14SSteve Longerbeam 	if (ret == 0)
209819a81c14SSteve Longerbeam 		return -EINVAL;
209919a81c14SSteve Longerbeam 	cap_sysclk = ret;
210019a81c14SSteve Longerbeam 
210119a81c14SSteve Longerbeam 	/* calculate capture banding filter */
210219a81c14SSteve Longerbeam 	ret = ov5640_get_light_freq(sensor);
210319a81c14SSteve Longerbeam 	if (ret < 0)
210419a81c14SSteve Longerbeam 		return ret;
210519a81c14SSteve Longerbeam 	light_freq = ret;
210619a81c14SSteve Longerbeam 
210719a81c14SSteve Longerbeam 	if (light_freq == 60) {
210819a81c14SSteve Longerbeam 		/* 60Hz */
210919a81c14SSteve Longerbeam 		cap_bandfilt = cap_sysclk * 100 / cap_hts * 100 / 120;
211019a81c14SSteve Longerbeam 	} else {
211119a81c14SSteve Longerbeam 		/* 50Hz */
211219a81c14SSteve Longerbeam 		cap_bandfilt = cap_sysclk * 100 / cap_hts;
211319a81c14SSteve Longerbeam 	}
211419a81c14SSteve Longerbeam 
211519a81c14SSteve Longerbeam 	if (!sensor->prev_sysclk) {
211619a81c14SSteve Longerbeam 		ret = ov5640_get_sysclk(sensor);
211719a81c14SSteve Longerbeam 		if (ret < 0)
211819a81c14SSteve Longerbeam 			return ret;
211919a81c14SSteve Longerbeam 		if (ret == 0)
212019a81c14SSteve Longerbeam 			return -EINVAL;
212119a81c14SSteve Longerbeam 		sensor->prev_sysclk = ret;
212219a81c14SSteve Longerbeam 	}
212319a81c14SSteve Longerbeam 
212419a81c14SSteve Longerbeam 	if (!cap_bandfilt)
212519a81c14SSteve Longerbeam 		return -EINVAL;
212619a81c14SSteve Longerbeam 
212719a81c14SSteve Longerbeam 	cap_maxband = (int)((cap_vts - 4) / cap_bandfilt);
212819a81c14SSteve Longerbeam 
212919a81c14SSteve Longerbeam 	/* calculate capture shutter/gain16 */
213019a81c14SSteve Longerbeam 	if (average > sensor->ae_low && average < sensor->ae_high) {
213119a81c14SSteve Longerbeam 		/* in stable range */
213219a81c14SSteve Longerbeam 		cap_gain16_shutter =
213319a81c14SSteve Longerbeam 			prev_gain16 * prev_shutter *
213419a81c14SSteve Longerbeam 			cap_sysclk / sensor->prev_sysclk *
213519a81c14SSteve Longerbeam 			sensor->prev_hts / cap_hts *
213619a81c14SSteve Longerbeam 			sensor->ae_target / average;
213719a81c14SSteve Longerbeam 	} else {
213819a81c14SSteve Longerbeam 		cap_gain16_shutter =
213919a81c14SSteve Longerbeam 			prev_gain16 * prev_shutter *
214019a81c14SSteve Longerbeam 			cap_sysclk / sensor->prev_sysclk *
214119a81c14SSteve Longerbeam 			sensor->prev_hts / cap_hts;
214219a81c14SSteve Longerbeam 	}
214319a81c14SSteve Longerbeam 
214419a81c14SSteve Longerbeam 	/* gain to shutter */
214519a81c14SSteve Longerbeam 	if (cap_gain16_shutter < (cap_bandfilt * 16)) {
214619a81c14SSteve Longerbeam 		/* shutter < 1/100 */
214719a81c14SSteve Longerbeam 		cap_shutter = cap_gain16_shutter / 16;
214819a81c14SSteve Longerbeam 		if (cap_shutter < 1)
214919a81c14SSteve Longerbeam 			cap_shutter = 1;
215019a81c14SSteve Longerbeam 
215119a81c14SSteve Longerbeam 		cap_gain16 = cap_gain16_shutter / cap_shutter;
215219a81c14SSteve Longerbeam 		if (cap_gain16 < 16)
215319a81c14SSteve Longerbeam 			cap_gain16 = 16;
215419a81c14SSteve Longerbeam 	} else {
215519a81c14SSteve Longerbeam 		if (cap_gain16_shutter > (cap_bandfilt * cap_maxband * 16)) {
215619a81c14SSteve Longerbeam 			/* exposure reach max */
215719a81c14SSteve Longerbeam 			cap_shutter = cap_bandfilt * cap_maxband;
215819a81c14SSteve Longerbeam 			if (!cap_shutter)
215919a81c14SSteve Longerbeam 				return -EINVAL;
216019a81c14SSteve Longerbeam 
216119a81c14SSteve Longerbeam 			cap_gain16 = cap_gain16_shutter / cap_shutter;
216219a81c14SSteve Longerbeam 		} else {
216319a81c14SSteve Longerbeam 			/* 1/100 < (cap_shutter = n/100) =< max */
216419a81c14SSteve Longerbeam 			cap_shutter =
216519a81c14SSteve Longerbeam 				((int)(cap_gain16_shutter / 16 / cap_bandfilt))
216619a81c14SSteve Longerbeam 				* cap_bandfilt;
216719a81c14SSteve Longerbeam 			if (!cap_shutter)
216819a81c14SSteve Longerbeam 				return -EINVAL;
216919a81c14SSteve Longerbeam 
217019a81c14SSteve Longerbeam 			cap_gain16 = cap_gain16_shutter / cap_shutter;
217119a81c14SSteve Longerbeam 		}
217219a81c14SSteve Longerbeam 	}
217319a81c14SSteve Longerbeam 
217419a81c14SSteve Longerbeam 	/* set capture gain */
21753cca8ef5SHugues Fruchet 	ret = ov5640_set_gain(sensor, cap_gain16);
217619a81c14SSteve Longerbeam 	if (ret)
217719a81c14SSteve Longerbeam 		return ret;
217819a81c14SSteve Longerbeam 
217919a81c14SSteve Longerbeam 	/* write capture shutter */
218019a81c14SSteve Longerbeam 	if (cap_shutter > (cap_vts - 4)) {
218119a81c14SSteve Longerbeam 		cap_vts = cap_shutter + 4;
218219a81c14SSteve Longerbeam 		ret = ov5640_set_vts(sensor, cap_vts);
218319a81c14SSteve Longerbeam 		if (ret < 0)
218419a81c14SSteve Longerbeam 			return ret;
218519a81c14SSteve Longerbeam 	}
218619a81c14SSteve Longerbeam 
218719a81c14SSteve Longerbeam 	/* set exposure */
21883cca8ef5SHugues Fruchet 	return ov5640_set_exposure(sensor, cap_shutter);
218919a81c14SSteve Longerbeam }
219019a81c14SSteve Longerbeam 
219119a81c14SSteve Longerbeam /*
219219a81c14SSteve Longerbeam  * if sensor changes inside scaling or subsampling
219319a81c14SSteve Longerbeam  * change mode directly
219419a81c14SSteve Longerbeam  */
219519a81c14SSteve Longerbeam static int ov5640_set_mode_direct(struct ov5640_dev *sensor,
21963cca8ef5SHugues Fruchet 				  const struct ov5640_mode_info *mode)
219719a81c14SSteve Longerbeam {
219841d8d7f5SHugues Fruchet 	if (!mode->reg_data)
219919a81c14SSteve Longerbeam 		return -EINVAL;
220019a81c14SSteve Longerbeam 
220119a81c14SSteve Longerbeam 	/* Write capture setting */
2202e4359019SJacopo Mondi 	ov5640_load_regs(sensor, mode->reg_data, mode->reg_data_size);
2203e4359019SJacopo Mondi 	return ov5640_set_timings(sensor, mode);
220419a81c14SSteve Longerbeam }
220519a81c14SSteve Longerbeam 
2206985cdcb0SHugues Fruchet static int ov5640_set_mode(struct ov5640_dev *sensor)
220719a81c14SSteve Longerbeam {
220819a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode = sensor->current_mode;
2209985cdcb0SHugues Fruchet 	const struct ov5640_mode_info *orig_mode = sensor->last_mode;
221019a81c14SSteve Longerbeam 	enum ov5640_downsize_mode dn_mode, orig_dn_mode;
22113cca8ef5SHugues Fruchet 	bool auto_gain = sensor->ctrls.auto_gain->val == 1;
2212dc29a1c1SHugues Fruchet 	bool auto_exp =  sensor->ctrls.auto_exp->val == V4L2_EXPOSURE_AUTO;
221319a81c14SSteve Longerbeam 	int ret;
221419a81c14SSteve Longerbeam 
221519a81c14SSteve Longerbeam 	dn_mode = mode->dn_mode;
221619a81c14SSteve Longerbeam 	orig_dn_mode = orig_mode->dn_mode;
221719a81c14SSteve Longerbeam 
221819a81c14SSteve Longerbeam 	/* auto gain and exposure must be turned off when changing modes */
22193cca8ef5SHugues Fruchet 	if (auto_gain) {
22203cca8ef5SHugues Fruchet 		ret = ov5640_set_autogain(sensor, false);
222119a81c14SSteve Longerbeam 		if (ret)
222219a81c14SSteve Longerbeam 			return ret;
22233cca8ef5SHugues Fruchet 	}
2224bf4a4b51SMaxime Ripard 
22253cca8ef5SHugues Fruchet 	if (auto_exp) {
2226dc29a1c1SHugues Fruchet 		ret = ov5640_set_autoexposure(sensor, false);
222719a81c14SSteve Longerbeam 		if (ret)
22283cca8ef5SHugues Fruchet 			goto restore_auto_gain;
22293cca8ef5SHugues Fruchet 	}
223019a81c14SSteve Longerbeam 
22316c957ed7SJacopo Mondi 	if (ov5640_is_csi2(sensor))
22326c957ed7SJacopo Mondi 		ret = ov5640_set_mipi_pclk(sensor);
22336c957ed7SJacopo Mondi 	else
22346c957ed7SJacopo Mondi 		ret = ov5640_set_dvp_pclk(sensor);
2235aa288248SMaxime Ripard 	if (ret < 0)
2236aa288248SMaxime Ripard 		return 0;
2237aa288248SMaxime Ripard 
223819a81c14SSteve Longerbeam 	if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) ||
223919a81c14SSteve Longerbeam 	    (dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) {
224019a81c14SSteve Longerbeam 		/*
224119a81c14SSteve Longerbeam 		 * change between subsampling and scaling
22423cca8ef5SHugues Fruchet 		 * go through exposure calculation
224319a81c14SSteve Longerbeam 		 */
224419a81c14SSteve Longerbeam 		ret = ov5640_set_mode_exposure_calc(sensor, mode);
224519a81c14SSteve Longerbeam 	} else {
224619a81c14SSteve Longerbeam 		/*
224719a81c14SSteve Longerbeam 		 * change inside subsampling or scaling
224819a81c14SSteve Longerbeam 		 * download firmware directly
224919a81c14SSteve Longerbeam 		 */
22503cca8ef5SHugues Fruchet 		ret = ov5640_set_mode_direct(sensor, mode);
225119a81c14SSteve Longerbeam 	}
225219a81c14SSteve Longerbeam 	if (ret < 0)
22533cca8ef5SHugues Fruchet 		goto restore_auto_exp_gain;
22543cca8ef5SHugues Fruchet 
22553cca8ef5SHugues Fruchet 	/* restore auto gain and exposure */
22563cca8ef5SHugues Fruchet 	if (auto_gain)
22573cca8ef5SHugues Fruchet 		ov5640_set_autogain(sensor, true);
22583cca8ef5SHugues Fruchet 	if (auto_exp)
22593cca8ef5SHugues Fruchet 		ov5640_set_autoexposure(sensor, true);
226019a81c14SSteve Longerbeam 
2261ce85705aSHugues Fruchet 	ret = ov5640_set_binning(sensor, dn_mode != SCALING);
2262ce85705aSHugues Fruchet 	if (ret < 0)
2263ce85705aSHugues Fruchet 		return ret;
226419a81c14SSteve Longerbeam 	ret = ov5640_set_ae_target(sensor, sensor->ae_target);
226519a81c14SSteve Longerbeam 	if (ret < 0)
226619a81c14SSteve Longerbeam 		return ret;
226719a81c14SSteve Longerbeam 	ret = ov5640_get_light_freq(sensor);
226819a81c14SSteve Longerbeam 	if (ret < 0)
226919a81c14SSteve Longerbeam 		return ret;
227019a81c14SSteve Longerbeam 	ret = ov5640_set_bandingfilter(sensor);
227119a81c14SSteve Longerbeam 	if (ret < 0)
227219a81c14SSteve Longerbeam 		return ret;
227319a81c14SSteve Longerbeam 	ret = ov5640_set_virtual_channel(sensor);
227419a81c14SSteve Longerbeam 	if (ret < 0)
227519a81c14SSteve Longerbeam 		return ret;
227619a81c14SSteve Longerbeam 
227719a81c14SSteve Longerbeam 	sensor->pending_mode_change = false;
2278985cdcb0SHugues Fruchet 	sensor->last_mode = mode;
227919a81c14SSteve Longerbeam 
228019a81c14SSteve Longerbeam 	return 0;
22813cca8ef5SHugues Fruchet 
22823cca8ef5SHugues Fruchet restore_auto_exp_gain:
22833cca8ef5SHugues Fruchet 	if (auto_exp)
22843cca8ef5SHugues Fruchet 		ov5640_set_autoexposure(sensor, true);
22853cca8ef5SHugues Fruchet restore_auto_gain:
22863cca8ef5SHugues Fruchet 	if (auto_gain)
22873cca8ef5SHugues Fruchet 		ov5640_set_autogain(sensor, true);
22883cca8ef5SHugues Fruchet 
22893cca8ef5SHugues Fruchet 	return ret;
229019a81c14SSteve Longerbeam }
229119a81c14SSteve Longerbeam 
229219ad26f9SAkinobu Mita static int ov5640_set_framefmt(struct ov5640_dev *sensor,
229319ad26f9SAkinobu Mita 			       struct v4l2_mbus_framefmt *format);
229419ad26f9SAkinobu Mita 
229519a81c14SSteve Longerbeam /* restore the last set video mode after chip power-on */
229619a81c14SSteve Longerbeam static int ov5640_restore_mode(struct ov5640_dev *sensor)
229719a81c14SSteve Longerbeam {
229819a81c14SSteve Longerbeam 	int ret;
229919a81c14SSteve Longerbeam 
230019a81c14SSteve Longerbeam 	/* first load the initial register values */
2301e4359019SJacopo Mondi 	ov5640_load_regs(sensor, ov5640_init_setting,
2302e4359019SJacopo Mondi 			 ARRAY_SIZE(ov5640_init_setting));
230319a81c14SSteve Longerbeam 
23048f57c2f8SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
23057851fe7aSMaxime Ripard 			     (ilog2(OV5640_SCLK2X_ROOT_DIV) << 2) |
23067851fe7aSMaxime Ripard 			     ilog2(OV5640_SCLK_ROOT_DIV));
23078f57c2f8SMaxime Ripard 	if (ret)
23088f57c2f8SMaxime Ripard 		return ret;
23098f57c2f8SMaxime Ripard 
231019a81c14SSteve Longerbeam 	/* now restore the last capture mode */
2311985cdcb0SHugues Fruchet 	ret = ov5640_set_mode(sensor);
231219ad26f9SAkinobu Mita 	if (ret < 0)
231319ad26f9SAkinobu Mita 		return ret;
231419ad26f9SAkinobu Mita 
231519ad26f9SAkinobu Mita 	return ov5640_set_framefmt(sensor, &sensor->fmt);
231619a81c14SSteve Longerbeam }
231719a81c14SSteve Longerbeam 
231819a81c14SSteve Longerbeam static void ov5640_power(struct ov5640_dev *sensor, bool enable)
231919a81c14SSteve Longerbeam {
23201fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->pwdn_gpio, enable ? 0 : 1);
232119a81c14SSteve Longerbeam }
232219a81c14SSteve Longerbeam 
232319a81c14SSteve Longerbeam static void ov5640_reset(struct ov5640_dev *sensor)
232419a81c14SSteve Longerbeam {
232519a81c14SSteve Longerbeam 	if (!sensor->reset_gpio)
232619a81c14SSteve Longerbeam 		return;
232719a81c14SSteve Longerbeam 
23281fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 0);
232919a81c14SSteve Longerbeam 
233019a81c14SSteve Longerbeam 	/* camera power cycle */
233119a81c14SSteve Longerbeam 	ov5640_power(sensor, false);
233219a81c14SSteve Longerbeam 	usleep_range(5000, 10000);
233319a81c14SSteve Longerbeam 	ov5640_power(sensor, true);
233419a81c14SSteve Longerbeam 	usleep_range(5000, 10000);
233519a81c14SSteve Longerbeam 
23361fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 1);
233719a81c14SSteve Longerbeam 	usleep_range(1000, 2000);
233819a81c14SSteve Longerbeam 
23391fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 0);
23401d4c41f3SLoic Poulain 	usleep_range(20000, 25000);
234119a81c14SSteve Longerbeam }
234219a81c14SSteve Longerbeam 
23430f7acb52SHugues Fruchet static int ov5640_set_power_on(struct ov5640_dev *sensor)
234419a81c14SSteve Longerbeam {
23450f7acb52SHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
23460f7acb52SHugues Fruchet 	int ret;
234719a81c14SSteve Longerbeam 
23480f7acb52SHugues Fruchet 	ret = clk_prepare_enable(sensor->xclk);
23490f7acb52SHugues Fruchet 	if (ret) {
23500f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to enable clock\n",
23510f7acb52SHugues Fruchet 			__func__);
23520f7acb52SHugues Fruchet 		return ret;
23530f7acb52SHugues Fruchet 	}
235419a81c14SSteve Longerbeam 
235519a81c14SSteve Longerbeam 	ret = regulator_bulk_enable(OV5640_NUM_SUPPLIES,
235619a81c14SSteve Longerbeam 				    sensor->supplies);
23570f7acb52SHugues Fruchet 	if (ret) {
23580f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to enable regulators\n",
23590f7acb52SHugues Fruchet 			__func__);
236019a81c14SSteve Longerbeam 		goto xclk_off;
23610f7acb52SHugues Fruchet 	}
236219a81c14SSteve Longerbeam 
236319a81c14SSteve Longerbeam 	ov5640_reset(sensor);
236419a81c14SSteve Longerbeam 	ov5640_power(sensor, true);
236519a81c14SSteve Longerbeam 
236619a81c14SSteve Longerbeam 	ret = ov5640_init_slave_id(sensor);
236719a81c14SSteve Longerbeam 	if (ret)
236819a81c14SSteve Longerbeam 		goto power_off;
236919a81c14SSteve Longerbeam 
23700f7acb52SHugues Fruchet 	return 0;
23710f7acb52SHugues Fruchet 
23720f7acb52SHugues Fruchet power_off:
23730f7acb52SHugues Fruchet 	ov5640_power(sensor, false);
23740f7acb52SHugues Fruchet 	regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies);
23750f7acb52SHugues Fruchet xclk_off:
23760f7acb52SHugues Fruchet 	clk_disable_unprepare(sensor->xclk);
23770f7acb52SHugues Fruchet 	return ret;
23780f7acb52SHugues Fruchet }
23790f7acb52SHugues Fruchet 
23800f7acb52SHugues Fruchet static void ov5640_set_power_off(struct ov5640_dev *sensor)
23810f7acb52SHugues Fruchet {
23820f7acb52SHugues Fruchet 	ov5640_power(sensor, false);
23830f7acb52SHugues Fruchet 	regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies);
23840f7acb52SHugues Fruchet 	clk_disable_unprepare(sensor->xclk);
23850f7acb52SHugues Fruchet }
23860f7acb52SHugues Fruchet 
2387b1751ae6SLad Prabhakar static int ov5640_set_power_mipi(struct ov5640_dev *sensor, bool on)
2388b1751ae6SLad Prabhakar {
2389b1751ae6SLad Prabhakar 	int ret;
2390b1751ae6SLad Prabhakar 
2391b1751ae6SLad Prabhakar 	if (!on) {
2392b1751ae6SLad Prabhakar 		/* Reset MIPI bus settings to their default values. */
2393b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
2394b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x04);
2395b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x00);
2396b1751ae6SLad Prabhakar 		return 0;
2397b1751ae6SLad Prabhakar 	}
2398b1751ae6SLad Prabhakar 
2399b1751ae6SLad Prabhakar 	/*
2400b1751ae6SLad Prabhakar 	 * Power up MIPI HS Tx and LS Rx; 2 data lanes mode
2401b1751ae6SLad Prabhakar 	 *
2402b1751ae6SLad Prabhakar 	 * 0x300e = 0x40
2403b1751ae6SLad Prabhakar 	 * [7:5] = 010	: 2 data lanes mode (see FIXME note in
2404b1751ae6SLad Prabhakar 	 *		  "ov5640_set_stream_mipi()")
2405b1751ae6SLad Prabhakar 	 * [4] = 0	: Power up MIPI HS Tx
2406b1751ae6SLad Prabhakar 	 * [3] = 0	: Power up MIPI LS Rx
2407b1751ae6SLad Prabhakar 	 * [2] = 0	: MIPI interface disabled
2408b1751ae6SLad Prabhakar 	 */
2409b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x40);
2410b1751ae6SLad Prabhakar 	if (ret)
2411b1751ae6SLad Prabhakar 		return ret;
2412b1751ae6SLad Prabhakar 
2413b1751ae6SLad Prabhakar 	/*
2414b1751ae6SLad Prabhakar 	 * Gate clock and set LP11 in 'no packets mode' (idle)
2415b1751ae6SLad Prabhakar 	 *
2416b1751ae6SLad Prabhakar 	 * 0x4800 = 0x24
2417b1751ae6SLad Prabhakar 	 * [5] = 1	: Gate clock when 'no packets'
2418b1751ae6SLad Prabhakar 	 * [2] = 1	: MIPI bus in LP11 when 'no packets'
2419b1751ae6SLad Prabhakar 	 */
2420b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x24);
2421b1751ae6SLad Prabhakar 	if (ret)
2422b1751ae6SLad Prabhakar 		return ret;
2423b1751ae6SLad Prabhakar 
2424b1751ae6SLad Prabhakar 	/*
2425b1751ae6SLad Prabhakar 	 * Set data lanes and clock in LP11 when 'sleeping'
2426b1751ae6SLad Prabhakar 	 *
2427b1751ae6SLad Prabhakar 	 * 0x3019 = 0x70
2428b1751ae6SLad Prabhakar 	 * [6] = 1	: MIPI data lane 2 in LP11 when 'sleeping'
2429b1751ae6SLad Prabhakar 	 * [5] = 1	: MIPI data lane 1 in LP11 when 'sleeping'
2430b1751ae6SLad Prabhakar 	 * [4] = 1	: MIPI clock lane in LP11 when 'sleeping'
2431b1751ae6SLad Prabhakar 	 */
2432b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x70);
2433b1751ae6SLad Prabhakar 	if (ret)
2434b1751ae6SLad Prabhakar 		return ret;
2435b1751ae6SLad Prabhakar 
2436b1751ae6SLad Prabhakar 	/* Give lanes some time to coax into LP11 state. */
2437b1751ae6SLad Prabhakar 	usleep_range(500, 1000);
2438b1751ae6SLad Prabhakar 
2439b1751ae6SLad Prabhakar 	return 0;
2440b1751ae6SLad Prabhakar }
2441b1751ae6SLad Prabhakar 
2442576f5d4bSLad Prabhakar static int ov5640_set_power_dvp(struct ov5640_dev *sensor, bool on)
2443576f5d4bSLad Prabhakar {
2444311a6408SLad Prabhakar 	unsigned int flags = sensor->ep.bus.parallel.flags;
244568579b32SHugues Fruchet 	bool bt656 = sensor->ep.bus_type == V4L2_MBUS_BT656;
244668579b32SHugues Fruchet 	u8 polarities = 0;
2447576f5d4bSLad Prabhakar 	int ret;
2448576f5d4bSLad Prabhakar 
2449576f5d4bSLad Prabhakar 	if (!on) {
2450576f5d4bSLad Prabhakar 		/* Reset settings to their default values. */
245168579b32SHugues Fruchet 		ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00, 0x00);
2452311a6408SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
2453311a6408SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, 0x20);
2454576f5d4bSLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01, 0x00);
2455576f5d4bSLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0x00);
2456576f5d4bSLad Prabhakar 		return 0;
2457576f5d4bSLad Prabhakar 	}
2458576f5d4bSLad Prabhakar 
2459576f5d4bSLad Prabhakar 	/*
2460311a6408SLad Prabhakar 	 * Note about parallel port configuration.
2461311a6408SLad Prabhakar 	 *
2462311a6408SLad Prabhakar 	 * When configured in parallel mode, the OV5640 will
2463311a6408SLad Prabhakar 	 * output 10 bits data on DVP data lines [9:0].
2464311a6408SLad Prabhakar 	 * If only 8 bits data are wanted, the 8 bits data lines
2465311a6408SLad Prabhakar 	 * of the camera interface must be physically connected
2466311a6408SLad Prabhakar 	 * on the DVP data lines [9:2].
2467311a6408SLad Prabhakar 	 *
2468311a6408SLad Prabhakar 	 * Control lines polarity can be configured through
2469311a6408SLad Prabhakar 	 * devicetree endpoint control lines properties.
2470311a6408SLad Prabhakar 	 * If no endpoint control lines properties are set,
2471311a6408SLad Prabhakar 	 * polarity will be as below:
2472311a6408SLad Prabhakar 	 * - VSYNC:	active high
2473311a6408SLad Prabhakar 	 * - HREF:	active low
2474311a6408SLad Prabhakar 	 * - PCLK:	active low
247568579b32SHugues Fruchet 	 *
247668579b32SHugues Fruchet 	 * VSYNC & HREF are not configured if BT656 bus mode is selected
2477311a6408SLad Prabhakar 	 */
247868579b32SHugues Fruchet 
247968579b32SHugues Fruchet 	/*
248068579b32SHugues Fruchet 	 * BT656 embedded synchronization configuration
248168579b32SHugues Fruchet 	 *
248268579b32SHugues Fruchet 	 * CCIR656 CTRL00
248368579b32SHugues Fruchet 	 * - [7]:	SYNC code selection (0: auto generate sync code,
248468579b32SHugues Fruchet 	 *		1: sync code from regs 0x4732-0x4735)
248568579b32SHugues Fruchet 	 * - [6]:	f value in CCIR656 SYNC code when fixed f value
248668579b32SHugues Fruchet 	 * - [5]:	Fixed f value
248768579b32SHugues Fruchet 	 * - [4:3]:	Blank toggle data options (00: data=1'h040/1'h200,
248868579b32SHugues Fruchet 	 *		01: data from regs 0x4736-0x4738, 10: always keep 0)
248968579b32SHugues Fruchet 	 * - [1]:	Clip data disable
249068579b32SHugues Fruchet 	 * - [0]:	CCIR656 mode enable
249168579b32SHugues Fruchet 	 *
249268579b32SHugues Fruchet 	 * Default CCIR656 SAV/EAV mode with default codes
249368579b32SHugues Fruchet 	 * SAV=0xff000080 & EAV=0xff00009d is enabled here with settings:
249468579b32SHugues Fruchet 	 * - CCIR656 mode enable
249568579b32SHugues Fruchet 	 * - auto generation of sync codes
249668579b32SHugues Fruchet 	 * - blank toggle data 1'h040/1'h200
249768579b32SHugues Fruchet 	 * - clip reserved data (0x00 & 0xff changed to 0x01 & 0xfe)
249868579b32SHugues Fruchet 	 */
249968579b32SHugues Fruchet 	ret = ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00,
250068579b32SHugues Fruchet 			       bt656 ? 0x01 : 0x00);
250168579b32SHugues Fruchet 	if (ret)
250268579b32SHugues Fruchet 		return ret;
250368579b32SHugues Fruchet 
2504311a6408SLad Prabhakar 	/*
2505311a6408SLad Prabhakar 	 * configure parallel port control lines polarity
2506311a6408SLad Prabhakar 	 *
2507311a6408SLad Prabhakar 	 * POLARITY CTRL0
2508311a6408SLad Prabhakar 	 * - [5]:	PCLK polarity (0: active low, 1: active high)
2509311a6408SLad Prabhakar 	 * - [1]:	HREF polarity (0: active low, 1: active high)
2510311a6408SLad Prabhakar 	 * - [0]:	VSYNC polarity (mismatch here between
2511311a6408SLad Prabhakar 	 *		datasheet and hardware, 0 is active high
2512311a6408SLad Prabhakar 	 *		and 1 is active low...)
2513311a6408SLad Prabhakar 	 */
251468579b32SHugues Fruchet 	if (!bt656) {
2515311a6408SLad Prabhakar 		if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
251668579b32SHugues Fruchet 			polarities |= BIT(1);
2517311a6408SLad Prabhakar 		if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
251868579b32SHugues Fruchet 			polarities |= BIT(0);
251968579b32SHugues Fruchet 	}
252068579b32SHugues Fruchet 	if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
252168579b32SHugues Fruchet 		polarities |= BIT(5);
2522311a6408SLad Prabhakar 
252368579b32SHugues Fruchet 	ret = ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, polarities);
2524311a6408SLad Prabhakar 	if (ret)
2525311a6408SLad Prabhakar 		return ret;
2526311a6408SLad Prabhakar 
2527311a6408SLad Prabhakar 	/*
252868579b32SHugues Fruchet 	 * powerdown MIPI TX/RX PHY & enable DVP
2529311a6408SLad Prabhakar 	 *
2530311a6408SLad Prabhakar 	 * MIPI CONTROL 00
253168579b32SHugues Fruchet 	 * [4] = 1	: Power down MIPI HS Tx
253268579b32SHugues Fruchet 	 * [3] = 1	: Power down MIPI LS Rx
253368579b32SHugues Fruchet 	 * [2] = 0	: DVP enable (MIPI disable)
2534311a6408SLad Prabhakar 	 */
2535311a6408SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x18);
2536311a6408SLad Prabhakar 	if (ret)
2537311a6408SLad Prabhakar 		return ret;
2538311a6408SLad Prabhakar 
2539311a6408SLad Prabhakar 	/*
2540576f5d4bSLad Prabhakar 	 * enable VSYNC/HREF/PCLK DVP control lines
2541576f5d4bSLad Prabhakar 	 * & D[9:6] DVP data lines
2542576f5d4bSLad Prabhakar 	 *
2543576f5d4bSLad Prabhakar 	 * PAD OUTPUT ENABLE 01
2544576f5d4bSLad Prabhakar 	 * - 6:		VSYNC output enable
2545576f5d4bSLad Prabhakar 	 * - 5:		HREF output enable
2546576f5d4bSLad Prabhakar 	 * - 4:		PCLK output enable
2547576f5d4bSLad Prabhakar 	 * - [3:0]:	D[9:6] output enable
2548576f5d4bSLad Prabhakar 	 */
25494039b037SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01,
255068579b32SHugues Fruchet 			       bt656 ? 0x1f : 0x7f);
2551576f5d4bSLad Prabhakar 	if (ret)
2552576f5d4bSLad Prabhakar 		return ret;
2553576f5d4bSLad Prabhakar 
2554576f5d4bSLad Prabhakar 	/*
2555576f5d4bSLad Prabhakar 	 * enable D[5:0] DVP data lines
2556576f5d4bSLad Prabhakar 	 *
2557576f5d4bSLad Prabhakar 	 * PAD OUTPUT ENABLE 02
2558576f5d4bSLad Prabhakar 	 * - [7:2]:	D[5:0] output enable
2559576f5d4bSLad Prabhakar 	 */
2560576f5d4bSLad Prabhakar 	return ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0xfc);
2561576f5d4bSLad Prabhakar }
2562576f5d4bSLad Prabhakar 
25630f7acb52SHugues Fruchet static int ov5640_set_power(struct ov5640_dev *sensor, bool on)
25640f7acb52SHugues Fruchet {
25650f7acb52SHugues Fruchet 	int ret = 0;
25660f7acb52SHugues Fruchet 
25670f7acb52SHugues Fruchet 	if (on) {
25680f7acb52SHugues Fruchet 		ret = ov5640_set_power_on(sensor);
25690f7acb52SHugues Fruchet 		if (ret)
25700f7acb52SHugues Fruchet 			return ret;
25710f7acb52SHugues Fruchet 
257219a81c14SSteve Longerbeam 		ret = ov5640_restore_mode(sensor);
257319a81c14SSteve Longerbeam 		if (ret)
257419a81c14SSteve Longerbeam 			goto power_off;
2575b1751ae6SLad Prabhakar 	}
257619a81c14SSteve Longerbeam 
2577576f5d4bSLad Prabhakar 	if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY)
2578b1751ae6SLad Prabhakar 		ret = ov5640_set_power_mipi(sensor, on);
2579576f5d4bSLad Prabhakar 	else
2580576f5d4bSLad Prabhakar 		ret = ov5640_set_power_dvp(sensor, on);
2581b1751ae6SLad Prabhakar 	if (ret)
2582b1751ae6SLad Prabhakar 		goto power_off;
2583aa4bb8b8SJacopo Mondi 
2584b1751ae6SLad Prabhakar 	if (!on)
2585aa4bb8b8SJacopo Mondi 		ov5640_set_power_off(sensor);
258619a81c14SSteve Longerbeam 
258719a81c14SSteve Longerbeam 	return 0;
258819a81c14SSteve Longerbeam 
258919a81c14SSteve Longerbeam power_off:
25900f7acb52SHugues Fruchet 	ov5640_set_power_off(sensor);
259119a81c14SSteve Longerbeam 	return ret;
259219a81c14SSteve Longerbeam }
259319a81c14SSteve Longerbeam 
259419a81c14SSteve Longerbeam /* --------------- Subdev Operations --------------- */
259519a81c14SSteve Longerbeam 
259619a81c14SSteve Longerbeam static int ov5640_s_power(struct v4l2_subdev *sd, int on)
259719a81c14SSteve Longerbeam {
259819a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
259919a81c14SSteve Longerbeam 	int ret = 0;
260019a81c14SSteve Longerbeam 
260119a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
260219a81c14SSteve Longerbeam 
260319a81c14SSteve Longerbeam 	/*
260419a81c14SSteve Longerbeam 	 * If the power count is modified from 0 to != 0 or from != 0 to 0,
260519a81c14SSteve Longerbeam 	 * update the power state.
260619a81c14SSteve Longerbeam 	 */
260719a81c14SSteve Longerbeam 	if (sensor->power_count == !on) {
260819a81c14SSteve Longerbeam 		ret = ov5640_set_power(sensor, !!on);
260919a81c14SSteve Longerbeam 		if (ret)
261019a81c14SSteve Longerbeam 			goto out;
261119a81c14SSteve Longerbeam 	}
261219a81c14SSteve Longerbeam 
261319a81c14SSteve Longerbeam 	/* Update the power count. */
261419a81c14SSteve Longerbeam 	sensor->power_count += on ? 1 : -1;
261519a81c14SSteve Longerbeam 	WARN_ON(sensor->power_count < 0);
261619a81c14SSteve Longerbeam out:
261719a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
261819a81c14SSteve Longerbeam 
261919a81c14SSteve Longerbeam 	if (on && !ret && sensor->power_count == 1) {
262019a81c14SSteve Longerbeam 		/* restore controls */
262119a81c14SSteve Longerbeam 		ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
262219a81c14SSteve Longerbeam 	}
262319a81c14SSteve Longerbeam 
262419a81c14SSteve Longerbeam 	return ret;
262519a81c14SSteve Longerbeam }
262619a81c14SSteve Longerbeam 
262719a81c14SSteve Longerbeam static int ov5640_try_frame_interval(struct ov5640_dev *sensor,
262819a81c14SSteve Longerbeam 				     struct v4l2_fract *fi,
262919a81c14SSteve Longerbeam 				     u32 width, u32 height)
263019a81c14SSteve Longerbeam {
263119a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
26326530a5ebSJagan Teki 	enum ov5640_frame_rate rate = OV5640_15_FPS;
2633f6cc192fSMaxime Ripard 	int minfps, maxfps, best_fps, fps;
2634f6cc192fSMaxime Ripard 	int i;
263519a81c14SSteve Longerbeam 
263619a81c14SSteve Longerbeam 	minfps = ov5640_framerates[OV5640_15_FPS];
2637e823fb16SMaxime Ripard 	maxfps = ov5640_framerates[OV5640_60_FPS];
263819a81c14SSteve Longerbeam 
263919a81c14SSteve Longerbeam 	if (fi->numerator == 0) {
264019a81c14SSteve Longerbeam 		fi->denominator = maxfps;
264119a81c14SSteve Longerbeam 		fi->numerator = 1;
2642e823fb16SMaxime Ripard 		rate = OV5640_60_FPS;
2643e823fb16SMaxime Ripard 		goto find_mode;
264419a81c14SSteve Longerbeam 	}
264519a81c14SSteve Longerbeam 
2646f6cc192fSMaxime Ripard 	fps = clamp_val(DIV_ROUND_CLOSEST(fi->denominator, fi->numerator),
2647f6cc192fSMaxime Ripard 			minfps, maxfps);
2648f6cc192fSMaxime Ripard 
2649f6cc192fSMaxime Ripard 	best_fps = minfps;
2650f6cc192fSMaxime Ripard 	for (i = 0; i < ARRAY_SIZE(ov5640_framerates); i++) {
2651f6cc192fSMaxime Ripard 		int curr_fps = ov5640_framerates[i];
2652f6cc192fSMaxime Ripard 
2653f6cc192fSMaxime Ripard 		if (abs(curr_fps - fps) < abs(best_fps - fps)) {
2654f6cc192fSMaxime Ripard 			best_fps = curr_fps;
2655f6cc192fSMaxime Ripard 			rate = i;
2656f6cc192fSMaxime Ripard 		}
2657f6cc192fSMaxime Ripard 	}
265819a81c14SSteve Longerbeam 
265919a81c14SSteve Longerbeam 	fi->numerator = 1;
2660f6cc192fSMaxime Ripard 	fi->denominator = best_fps;
266119a81c14SSteve Longerbeam 
2662e823fb16SMaxime Ripard find_mode:
2663b6ae5022SJacopo Mondi 	mode = ov5640_find_mode(sensor, width, height, false);
26645a3ad937SMaxime Ripard 	return mode ? rate : -EINVAL;
266519a81c14SSteve Longerbeam }
266619a81c14SSteve Longerbeam 
266719a81c14SSteve Longerbeam static int ov5640_get_fmt(struct v4l2_subdev *sd,
26680d346d2aSTomi Valkeinen 			  struct v4l2_subdev_state *sd_state,
266919a81c14SSteve Longerbeam 			  struct v4l2_subdev_format *format)
267019a81c14SSteve Longerbeam {
267119a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
267219a81c14SSteve Longerbeam 	struct v4l2_mbus_framefmt *fmt;
267319a81c14SSteve Longerbeam 
267419a81c14SSteve Longerbeam 	if (format->pad != 0)
267519a81c14SSteve Longerbeam 		return -EINVAL;
267619a81c14SSteve Longerbeam 
267719a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
267819a81c14SSteve Longerbeam 
267919a81c14SSteve Longerbeam 	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
26800d346d2aSTomi Valkeinen 		fmt = v4l2_subdev_get_try_format(&sensor->sd, sd_state,
268119a81c14SSteve Longerbeam 						 format->pad);
268219a81c14SSteve Longerbeam 	else
268319a81c14SSteve Longerbeam 		fmt = &sensor->fmt;
268419a81c14SSteve Longerbeam 
268519a81c14SSteve Longerbeam 	format->format = *fmt;
268619a81c14SSteve Longerbeam 
268719a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
268819a81c14SSteve Longerbeam 
268919a81c14SSteve Longerbeam 	return 0;
269019a81c14SSteve Longerbeam }
269119a81c14SSteve Longerbeam 
269219a81c14SSteve Longerbeam static int ov5640_try_fmt_internal(struct v4l2_subdev *sd,
269319a81c14SSteve Longerbeam 				   struct v4l2_mbus_framefmt *fmt,
269419a81c14SSteve Longerbeam 				   enum ov5640_frame_rate fr,
269519a81c14SSteve Longerbeam 				   const struct ov5640_mode_info **new_mode)
269619a81c14SSteve Longerbeam {
269719a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
269819a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
2699e3ee691dSHugues Fruchet 	int i;
270019a81c14SSteve Longerbeam 
2701b6ae5022SJacopo Mondi 	mode = ov5640_find_mode(sensor, fmt->width, fmt->height, true);
270219a81c14SSteve Longerbeam 	if (!mode)
270319a81c14SSteve Longerbeam 		return -EINVAL;
27045113d5b3SJacopo Mondi 	fmt->width = mode->width;
27055113d5b3SJacopo Mondi 	fmt->height = mode->height;
270619a81c14SSteve Longerbeam 
270719a81c14SSteve Longerbeam 	if (new_mode)
270819a81c14SSteve Longerbeam 		*new_mode = mode;
2709e3ee691dSHugues Fruchet 
2710e3ee691dSHugues Fruchet 	for (i = 0; i < ARRAY_SIZE(ov5640_formats); i++)
2711e3ee691dSHugues Fruchet 		if (ov5640_formats[i].code == fmt->code)
2712e3ee691dSHugues Fruchet 			break;
2713e3ee691dSHugues Fruchet 	if (i >= ARRAY_SIZE(ov5640_formats))
2714e6441fdeSHugues Fruchet 		i = 0;
2715e6441fdeSHugues Fruchet 
2716e6441fdeSHugues Fruchet 	fmt->code = ov5640_formats[i].code;
2717e6441fdeSHugues Fruchet 	fmt->colorspace = ov5640_formats[i].colorspace;
2718e6441fdeSHugues Fruchet 	fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
2719e6441fdeSHugues Fruchet 	fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
2720e6441fdeSHugues Fruchet 	fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
2721e3ee691dSHugues Fruchet 
272219a81c14SSteve Longerbeam 	return 0;
272319a81c14SSteve Longerbeam }
272419a81c14SSteve Longerbeam 
27253c28588fSJacopo Mondi static int ov5640_update_pixel_rate(struct ov5640_dev *sensor)
27263c28588fSJacopo Mondi {
27273c28588fSJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
27283c28588fSJacopo Mondi 	enum ov5640_pixel_rate_id pixel_rate_id = mode->pixel_rate;
27293c28588fSJacopo Mondi 	struct v4l2_mbus_framefmt *fmt = &sensor->fmt;
273032979f67SJacopo Mondi 	const struct ov5640_timings *timings;
2731bce93b82SJacopo Mondi 	s32 exposure_val, exposure_max;
273232979f67SJacopo Mondi 	unsigned int hblank;
27333c28588fSJacopo Mondi 	unsigned int i = 0;
27343c28588fSJacopo Mondi 	u32 pixel_rate;
27353c28588fSJacopo Mondi 	s64 link_freq;
27363c28588fSJacopo Mondi 	u32 num_lanes;
273719f2e3e6SHugues Fruchet 	u32 vblank;
27383c28588fSJacopo Mondi 	u32 bpp;
27393c28588fSJacopo Mondi 
27403c28588fSJacopo Mondi 	/*
27413c28588fSJacopo Mondi 	 * Update the pixel rate control value.
27423c28588fSJacopo Mondi 	 *
27433c28588fSJacopo Mondi 	 * For DVP mode, maintain the pixel rate calculation using fixed FPS.
27443c28588fSJacopo Mondi 	 */
27453c28588fSJacopo Mondi 	if (!ov5640_is_csi2(sensor)) {
27463c28588fSJacopo Mondi 		__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate,
27473c28588fSJacopo Mondi 					 ov5640_calc_pixel_rate(sensor));
27483c28588fSJacopo Mondi 
27493c28588fSJacopo Mondi 		return 0;
27503c28588fSJacopo Mondi 	}
27513c28588fSJacopo Mondi 
27523c28588fSJacopo Mondi 	/*
27533c28588fSJacopo Mondi 	 * The MIPI CSI-2 link frequency should comply with the CSI-2
27543c28588fSJacopo Mondi 	 * specification and be lower than 1GHz.
27553c28588fSJacopo Mondi 	 *
27563c28588fSJacopo Mondi 	 * Start from the suggested pixel_rate for the current mode and
27573c28588fSJacopo Mondi 	 * progressively slow it down if it exceeds 1GHz.
27583c28588fSJacopo Mondi 	 */
27593c28588fSJacopo Mondi 	num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes;
27603c28588fSJacopo Mondi 	bpp = ov5640_code_to_bpp(fmt->code);
27613c28588fSJacopo Mondi 	do {
27623c28588fSJacopo Mondi 		pixel_rate = ov5640_pixel_rates[pixel_rate_id];
27633c28588fSJacopo Mondi 		link_freq = pixel_rate * bpp / (2 * num_lanes);
27643c28588fSJacopo Mondi 	} while (link_freq >= 1000000000U &&
27653c28588fSJacopo Mondi 		 ++pixel_rate_id < OV5640_NUM_PIXEL_RATES);
27663c28588fSJacopo Mondi 
27673c28588fSJacopo Mondi 	sensor->current_link_freq = link_freq;
27683c28588fSJacopo Mondi 
27693c28588fSJacopo Mondi 	/*
27703c28588fSJacopo Mondi 	 * Higher link rates require the clock tree to be programmed with
27713c28588fSJacopo Mondi 	 * 'mipi_div' = 1; this has the effect of halving the actual output
27723c28588fSJacopo Mondi 	 * pixel rate in the MIPI domain.
27733c28588fSJacopo Mondi 	 *
27743c28588fSJacopo Mondi 	 * Adjust the pixel rate and link frequency control value to report it
27753c28588fSJacopo Mondi 	 * correctly to userspace.
27763c28588fSJacopo Mondi 	 */
27773c28588fSJacopo Mondi 	if (link_freq > OV5640_LINK_RATE_MAX) {
27783c28588fSJacopo Mondi 		pixel_rate /= 2;
27793c28588fSJacopo Mondi 		link_freq /= 2;
27803c28588fSJacopo Mondi 	}
27813c28588fSJacopo Mondi 
27823c28588fSJacopo Mondi 	for (i = 0; i < ARRAY_SIZE(ov5640_csi2_link_freqs); ++i) {
27833c28588fSJacopo Mondi 		if (ov5640_csi2_link_freqs[i] == link_freq)
27843c28588fSJacopo Mondi 			break;
27853c28588fSJacopo Mondi 	}
27863c28588fSJacopo Mondi 	WARN_ON(i == ARRAY_SIZE(ov5640_csi2_link_freqs));
27873c28588fSJacopo Mondi 
27883c28588fSJacopo Mondi 	__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, pixel_rate);
27893c28588fSJacopo Mondi 	__v4l2_ctrl_s_ctrl(sensor->ctrls.link_freq, i);
27903c28588fSJacopo Mondi 
279132979f67SJacopo Mondi 	timings = ov5640_timings(sensor, mode);
279232979f67SJacopo Mondi 	hblank = timings->htot - mode->width;
279332979f67SJacopo Mondi 	__v4l2_ctrl_modify_range(sensor->ctrls.hblank,
279432979f67SJacopo Mondi 				 hblank, hblank, 1, hblank);
279532979f67SJacopo Mondi 
279619f2e3e6SHugues Fruchet 	vblank = timings->vblank_def;
2797bce93b82SJacopo Mondi 
279819f2e3e6SHugues Fruchet 	if (sensor->current_fr != mode->def_fps) {
279919f2e3e6SHugues Fruchet 		/*
280019f2e3e6SHugues Fruchet 		 * Compute the vertical blanking according to the framerate
280119f2e3e6SHugues Fruchet 		 * configured with s_frame_interval.
280219f2e3e6SHugues Fruchet 		 */
280319f2e3e6SHugues Fruchet 		int fie_num = sensor->frame_interval.numerator;
280419f2e3e6SHugues Fruchet 		int fie_denom = sensor->frame_interval.denominator;
280519f2e3e6SHugues Fruchet 
280619f2e3e6SHugues Fruchet 		vblank = ((fie_num * pixel_rate / fie_denom) / timings->htot) -
280719f2e3e6SHugues Fruchet 			mode->height;
280819f2e3e6SHugues Fruchet 	}
280919f2e3e6SHugues Fruchet 
281019f2e3e6SHugues Fruchet 	__v4l2_ctrl_modify_range(sensor->ctrls.vblank, OV5640_MIN_VBLANK,
281119f2e3e6SHugues Fruchet 				 OV5640_MAX_VTS - mode->height, 1, vblank);
281219f2e3e6SHugues Fruchet 	__v4l2_ctrl_s_ctrl(sensor->ctrls.vblank, vblank);
281319f2e3e6SHugues Fruchet 
281419f2e3e6SHugues Fruchet 	exposure_max = timings->crop.height + vblank - 4;
2815bce93b82SJacopo Mondi 	exposure_val = clamp_t(s32, sensor->ctrls.exposure->val,
2816bce93b82SJacopo Mondi 			       sensor->ctrls.exposure->minimum,
2817bce93b82SJacopo Mondi 			       exposure_max);
281819f2e3e6SHugues Fruchet 
2819bce93b82SJacopo Mondi 	__v4l2_ctrl_modify_range(sensor->ctrls.exposure,
2820bce93b82SJacopo Mondi 				 sensor->ctrls.exposure->minimum,
2821bce93b82SJacopo Mondi 				 exposure_max, 1, exposure_val);
2822bce93b82SJacopo Mondi 
28233c28588fSJacopo Mondi 	return 0;
28243c28588fSJacopo Mondi }
28253c28588fSJacopo Mondi 
282619a81c14SSteve Longerbeam static int ov5640_set_fmt(struct v4l2_subdev *sd,
28270d346d2aSTomi Valkeinen 			  struct v4l2_subdev_state *sd_state,
282819a81c14SSteve Longerbeam 			  struct v4l2_subdev_format *format)
282919a81c14SSteve Longerbeam {
283019a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
283119a81c14SSteve Longerbeam 	const struct ov5640_mode_info *new_mode;
2832e6441fdeSHugues Fruchet 	struct v4l2_mbus_framefmt *mbus_fmt = &format->format;
283319a81c14SSteve Longerbeam 	int ret;
283419a81c14SSteve Longerbeam 
283519a81c14SSteve Longerbeam 	if (format->pad != 0)
283619a81c14SSteve Longerbeam 		return -EINVAL;
283719a81c14SSteve Longerbeam 
283819a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
283919a81c14SSteve Longerbeam 
284019a81c14SSteve Longerbeam 	if (sensor->streaming) {
284119a81c14SSteve Longerbeam 		ret = -EBUSY;
284219a81c14SSteve Longerbeam 		goto out;
284319a81c14SSteve Longerbeam 	}
284419a81c14SSteve Longerbeam 
2845e6441fdeSHugues Fruchet 	ret = ov5640_try_fmt_internal(sd, mbus_fmt,
284619a81c14SSteve Longerbeam 				      sensor->current_fr, &new_mode);
284719a81c14SSteve Longerbeam 	if (ret)
284819a81c14SSteve Longerbeam 		goto out;
284919a81c14SSteve Longerbeam 
2850e738f5ddSMirela Rabulea 	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
2851e738f5ddSMirela Rabulea 		*v4l2_subdev_get_try_format(sd, sd_state, 0) = *mbus_fmt;
2852e738f5ddSMirela Rabulea 		goto out;
2853e738f5ddSMirela Rabulea 	}
285419a81c14SSteve Longerbeam 
28556949d864SHugues Fruchet 	if (new_mode != sensor->current_mode) {
285619f2e3e6SHugues Fruchet 		sensor->current_fr = new_mode->def_fps;
285719a81c14SSteve Longerbeam 		sensor->current_mode = new_mode;
285819a81c14SSteve Longerbeam 		sensor->pending_mode_change = true;
28596949d864SHugues Fruchet 	}
286007115449SJacopo Mondi 	if (mbus_fmt->code != sensor->fmt.code)
2861fb98e29fSHugues Fruchet 		sensor->pending_fmt_change = true;
286207115449SJacopo Mondi 
2863e738f5ddSMirela Rabulea 	/* update format even if code is unchanged, resolution might change */
2864e738f5ddSMirela Rabulea 	sensor->fmt = *mbus_fmt;
2865e738f5ddSMirela Rabulea 
28663c28588fSJacopo Mondi 	ov5640_update_pixel_rate(sensor);
28673c28588fSJacopo Mondi 
286819a81c14SSteve Longerbeam out:
286919a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
287019a81c14SSteve Longerbeam 	return ret;
287119a81c14SSteve Longerbeam }
287219a81c14SSteve Longerbeam 
287366ed85ebSJacopo Mondi static int ov5640_get_selection(struct v4l2_subdev *sd,
287466ed85ebSJacopo Mondi 				struct v4l2_subdev_state *sd_state,
287566ed85ebSJacopo Mondi 				struct v4l2_subdev_selection *sel)
287666ed85ebSJacopo Mondi {
287766ed85ebSJacopo Mondi 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
287866ed85ebSJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
287966ed85ebSJacopo Mondi 	const struct ov5640_timings *timings;
288066ed85ebSJacopo Mondi 
288166ed85ebSJacopo Mondi 	switch (sel->target) {
288266ed85ebSJacopo Mondi 	case V4L2_SEL_TGT_CROP: {
288366ed85ebSJacopo Mondi 		mutex_lock(&sensor->lock);
288466ed85ebSJacopo Mondi 		timings = ov5640_timings(sensor, mode);
288566ed85ebSJacopo Mondi 		sel->r = timings->analog_crop;
288666ed85ebSJacopo Mondi 		mutex_unlock(&sensor->lock);
288766ed85ebSJacopo Mondi 
288866ed85ebSJacopo Mondi 		return 0;
288966ed85ebSJacopo Mondi 	}
289066ed85ebSJacopo Mondi 
289166ed85ebSJacopo Mondi 	case V4L2_SEL_TGT_NATIVE_SIZE:
289266ed85ebSJacopo Mondi 	case V4L2_SEL_TGT_CROP_BOUNDS:
289366ed85ebSJacopo Mondi 		sel->r.top = 0;
289466ed85ebSJacopo Mondi 		sel->r.left = 0;
289566ed85ebSJacopo Mondi 		sel->r.width = OV5640_NATIVE_WIDTH;
289666ed85ebSJacopo Mondi 		sel->r.height = OV5640_NATIVE_HEIGHT;
289766ed85ebSJacopo Mondi 
289866ed85ebSJacopo Mondi 		return 0;
289966ed85ebSJacopo Mondi 
290066ed85ebSJacopo Mondi 	case V4L2_SEL_TGT_CROP_DEFAULT:
290166ed85ebSJacopo Mondi 		sel->r.top = OV5640_PIXEL_ARRAY_TOP;
290266ed85ebSJacopo Mondi 		sel->r.left = OV5640_PIXEL_ARRAY_LEFT;
290366ed85ebSJacopo Mondi 		sel->r.width = OV5640_PIXEL_ARRAY_WIDTH;
290466ed85ebSJacopo Mondi 		sel->r.height = OV5640_PIXEL_ARRAY_HEIGHT;
290566ed85ebSJacopo Mondi 
290666ed85ebSJacopo Mondi 		return 0;
290766ed85ebSJacopo Mondi 	}
290866ed85ebSJacopo Mondi 
290966ed85ebSJacopo Mondi 	return -EINVAL;
291066ed85ebSJacopo Mondi }
291166ed85ebSJacopo Mondi 
2912e3ee691dSHugues Fruchet static int ov5640_set_framefmt(struct ov5640_dev *sensor,
2913e3ee691dSHugues Fruchet 			       struct v4l2_mbus_framefmt *format)
2914e3ee691dSHugues Fruchet {
2915e3ee691dSHugues Fruchet 	int ret = 0;
2916d47c4126SHugues Fruchet 	bool is_jpeg = false;
2917b7ed3abdSLoic Poulain 	u8 fmt, mux;
2918e3ee691dSHugues Fruchet 
2919e3ee691dSHugues Fruchet 	switch (format->code) {
29201536fbdbSXavier Roumegue 	case MEDIA_BUS_FMT_UYVY8_1X16:
2921e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_UYVY8_2X8:
2922e3ee691dSHugues Fruchet 		/* YUV422, UYVY */
2923b7ed3abdSLoic Poulain 		fmt = 0x3f;
2924b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_YUV422;
2925e3ee691dSHugues Fruchet 		break;
29261536fbdbSXavier Roumegue 	case MEDIA_BUS_FMT_YUYV8_1X16:
2927e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_YUYV8_2X8:
2928e3ee691dSHugues Fruchet 		/* YUV422, YUYV */
2929b7ed3abdSLoic Poulain 		fmt = 0x30;
2930b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_YUV422;
2931e3ee691dSHugues Fruchet 		break;
2932e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_RGB565_2X8_LE:
2933*0a43fcd7SJacopo Mondi 	case MEDIA_BUS_FMT_RGB565_1X16:
2934e3ee691dSHugues Fruchet 		/* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */
2935b7ed3abdSLoic Poulain 		fmt = 0x6F;
2936b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RGB;
2937e3ee691dSHugues Fruchet 		break;
2938e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_RGB565_2X8_BE:
2939e3ee691dSHugues Fruchet 		/* RGB565 {r[4:0],g[5:3]},{g[2:0],b[4:0]} */
2940b7ed3abdSLoic Poulain 		fmt = 0x61;
2941b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RGB;
2942e3ee691dSHugues Fruchet 		break;
2943d47c4126SHugues Fruchet 	case MEDIA_BUS_FMT_JPEG_1X8:
2944d47c4126SHugues Fruchet 		/* YUV422, YUYV */
2945b7ed3abdSLoic Poulain 		fmt = 0x30;
2946b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_YUV422;
2947d47c4126SHugues Fruchet 		is_jpeg = true;
2948d47c4126SHugues Fruchet 		break;
2949b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SBGGR8_1X8:
2950b7ed3abdSLoic Poulain 		/* Raw, BGBG... / GRGR... */
2951b7ed3abdSLoic Poulain 		fmt = 0x00;
2952b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2953b7ed3abdSLoic Poulain 		break;
2954b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SGBRG8_1X8:
2955b7ed3abdSLoic Poulain 		/* Raw bayer, GBGB... / RGRG... */
2956b7ed3abdSLoic Poulain 		fmt = 0x01;
2957b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2958b7ed3abdSLoic Poulain 		break;
2959b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SGRBG8_1X8:
2960b7ed3abdSLoic Poulain 		/* Raw bayer, GRGR... / BGBG... */
2961b7ed3abdSLoic Poulain 		fmt = 0x02;
2962b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2963b7ed3abdSLoic Poulain 		break;
2964b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SRGGB8_1X8:
2965b7ed3abdSLoic Poulain 		/* Raw bayer, RGRG... / GBGB... */
2966b7ed3abdSLoic Poulain 		fmt = 0x03;
2967b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2968b7ed3abdSLoic Poulain 		break;
2969e3ee691dSHugues Fruchet 	default:
2970e3ee691dSHugues Fruchet 		return -EINVAL;
2971e3ee691dSHugues Fruchet 	}
2972e3ee691dSHugues Fruchet 
2973e3ee691dSHugues Fruchet 	/* FORMAT CONTROL00: YUV and RGB formatting */
2974b7ed3abdSLoic Poulain 	ret = ov5640_write_reg(sensor, OV5640_REG_FORMAT_CONTROL00, fmt);
2975e3ee691dSHugues Fruchet 	if (ret)
2976e3ee691dSHugues Fruchet 		return ret;
2977e3ee691dSHugues Fruchet 
2978e3ee691dSHugues Fruchet 	/* FORMAT MUX CONTROL: ISP YUV or RGB */
2979b7ed3abdSLoic Poulain 	ret = ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL, mux);
2980d47c4126SHugues Fruchet 	if (ret)
2981d47c4126SHugues Fruchet 		return ret;
2982d47c4126SHugues Fruchet 
2983d47c4126SHugues Fruchet 	/*
2984d47c4126SHugues Fruchet 	 * TIMING TC REG21:
2985d47c4126SHugues Fruchet 	 * - [5]:	JPEG enable
2986d47c4126SHugues Fruchet 	 */
2987d47c4126SHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
2988d47c4126SHugues Fruchet 			     BIT(5), is_jpeg ? BIT(5) : 0);
2989d47c4126SHugues Fruchet 	if (ret)
2990d47c4126SHugues Fruchet 		return ret;
2991d47c4126SHugues Fruchet 
2992d47c4126SHugues Fruchet 	/*
2993d47c4126SHugues Fruchet 	 * SYSTEM RESET02:
2994d47c4126SHugues Fruchet 	 * - [4]:	Reset JFIFO
2995d47c4126SHugues Fruchet 	 * - [3]:	Reset SFIFO
2996d47c4126SHugues Fruchet 	 * - [2]:	Reset JPEG
2997d47c4126SHugues Fruchet 	 */
2998d47c4126SHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_RESET02,
2999d47c4126SHugues Fruchet 			     BIT(4) | BIT(3) | BIT(2),
3000d47c4126SHugues Fruchet 			     is_jpeg ? 0 : (BIT(4) | BIT(3) | BIT(2)));
3001d47c4126SHugues Fruchet 	if (ret)
3002d47c4126SHugues Fruchet 		return ret;
3003d47c4126SHugues Fruchet 
3004d47c4126SHugues Fruchet 	/*
3005d47c4126SHugues Fruchet 	 * CLOCK ENABLE02:
3006d47c4126SHugues Fruchet 	 * - [5]:	Enable JPEG 2x clock
3007d47c4126SHugues Fruchet 	 * - [3]:	Enable JPEG clock
3008d47c4126SHugues Fruchet 	 */
3009d47c4126SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_SYS_CLOCK_ENABLE02,
3010d47c4126SHugues Fruchet 			      BIT(5) | BIT(3),
3011d47c4126SHugues Fruchet 			      is_jpeg ? (BIT(5) | BIT(3)) : 0);
3012e3ee691dSHugues Fruchet }
301319a81c14SSteve Longerbeam 
301419a81c14SSteve Longerbeam /*
301519a81c14SSteve Longerbeam  * Sensor Controls.
301619a81c14SSteve Longerbeam  */
301719a81c14SSteve Longerbeam 
301819a81c14SSteve Longerbeam static int ov5640_set_ctrl_hue(struct ov5640_dev *sensor, int value)
301919a81c14SSteve Longerbeam {
302019a81c14SSteve Longerbeam 	int ret;
302119a81c14SSteve Longerbeam 
302219a81c14SSteve Longerbeam 	if (value) {
302319a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
302419a81c14SSteve Longerbeam 				     BIT(0), BIT(0));
302519a81c14SSteve Longerbeam 		if (ret)
302619a81c14SSteve Longerbeam 			return ret;
302719a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_SDE_CTRL1, value);
302819a81c14SSteve Longerbeam 	} else {
302919a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(0), 0);
303019a81c14SSteve Longerbeam 	}
303119a81c14SSteve Longerbeam 
303219a81c14SSteve Longerbeam 	return ret;
303319a81c14SSteve Longerbeam }
303419a81c14SSteve Longerbeam 
303519a81c14SSteve Longerbeam static int ov5640_set_ctrl_contrast(struct ov5640_dev *sensor, int value)
303619a81c14SSteve Longerbeam {
303719a81c14SSteve Longerbeam 	int ret;
303819a81c14SSteve Longerbeam 
303919a81c14SSteve Longerbeam 	if (value) {
304019a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
304119a81c14SSteve Longerbeam 				     BIT(2), BIT(2));
304219a81c14SSteve Longerbeam 		if (ret)
304319a81c14SSteve Longerbeam 			return ret;
304419a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL5,
304519a81c14SSteve Longerbeam 				       value & 0xff);
304619a81c14SSteve Longerbeam 	} else {
304719a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(2), 0);
304819a81c14SSteve Longerbeam 	}
304919a81c14SSteve Longerbeam 
305019a81c14SSteve Longerbeam 	return ret;
305119a81c14SSteve Longerbeam }
305219a81c14SSteve Longerbeam 
305319a81c14SSteve Longerbeam static int ov5640_set_ctrl_saturation(struct ov5640_dev *sensor, int value)
305419a81c14SSteve Longerbeam {
305519a81c14SSteve Longerbeam 	int ret;
305619a81c14SSteve Longerbeam 
305719a81c14SSteve Longerbeam 	if (value) {
305819a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
305919a81c14SSteve Longerbeam 				     BIT(1), BIT(1));
306019a81c14SSteve Longerbeam 		if (ret)
306119a81c14SSteve Longerbeam 			return ret;
306219a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL3,
306319a81c14SSteve Longerbeam 				       value & 0xff);
306419a81c14SSteve Longerbeam 		if (ret)
306519a81c14SSteve Longerbeam 			return ret;
306619a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL4,
306719a81c14SSteve Longerbeam 				       value & 0xff);
306819a81c14SSteve Longerbeam 	} else {
306919a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(1), 0);
307019a81c14SSteve Longerbeam 	}
307119a81c14SSteve Longerbeam 
307219a81c14SSteve Longerbeam 	return ret;
307319a81c14SSteve Longerbeam }
307419a81c14SSteve Longerbeam 
307519a81c14SSteve Longerbeam static int ov5640_set_ctrl_white_balance(struct ov5640_dev *sensor, int awb)
307619a81c14SSteve Longerbeam {
307719a81c14SSteve Longerbeam 	int ret;
307819a81c14SSteve Longerbeam 
307919a81c14SSteve Longerbeam 	ret = ov5640_mod_reg(sensor, OV5640_REG_AWB_MANUAL_CTRL,
308019a81c14SSteve Longerbeam 			     BIT(0), awb ? 0 : 1);
308119a81c14SSteve Longerbeam 	if (ret)
308219a81c14SSteve Longerbeam 		return ret;
308319a81c14SSteve Longerbeam 
308419a81c14SSteve Longerbeam 	if (!awb) {
308519a81c14SSteve Longerbeam 		u16 red = (u16)sensor->ctrls.red_balance->val;
308619a81c14SSteve Longerbeam 		u16 blue = (u16)sensor->ctrls.blue_balance->val;
308719a81c14SSteve Longerbeam 
308819a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_R_GAIN, red);
308919a81c14SSteve Longerbeam 		if (ret)
309019a81c14SSteve Longerbeam 			return ret;
309119a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_B_GAIN, blue);
309219a81c14SSteve Longerbeam 	}
309319a81c14SSteve Longerbeam 
309419a81c14SSteve Longerbeam 	return ret;
309519a81c14SSteve Longerbeam }
309619a81c14SSteve Longerbeam 
30973cca8ef5SHugues Fruchet static int ov5640_set_ctrl_exposure(struct ov5640_dev *sensor,
30983cca8ef5SHugues Fruchet 				    enum v4l2_exposure_auto_type auto_exposure)
309919a81c14SSteve Longerbeam {
310019a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
31013cca8ef5SHugues Fruchet 	bool auto_exp = (auto_exposure == V4L2_EXPOSURE_AUTO);
310219a81c14SSteve Longerbeam 	int ret = 0;
310319a81c14SSteve Longerbeam 
310419a81c14SSteve Longerbeam 	if (ctrls->auto_exp->is_new) {
31053cca8ef5SHugues Fruchet 		ret = ov5640_set_autoexposure(sensor, auto_exp);
310619a81c14SSteve Longerbeam 		if (ret)
310719a81c14SSteve Longerbeam 			return ret;
310819a81c14SSteve Longerbeam 	}
310919a81c14SSteve Longerbeam 
31103cca8ef5SHugues Fruchet 	if (!auto_exp && ctrls->exposure->is_new) {
311119a81c14SSteve Longerbeam 		u16 max_exp;
311219a81c14SSteve Longerbeam 
311319a81c14SSteve Longerbeam 		ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_VTS,
311419a81c14SSteve Longerbeam 					&max_exp);
311519a81c14SSteve Longerbeam 		if (ret)
311619a81c14SSteve Longerbeam 			return ret;
311719a81c14SSteve Longerbeam 		ret = ov5640_get_vts(sensor);
311819a81c14SSteve Longerbeam 		if (ret < 0)
311919a81c14SSteve Longerbeam 			return ret;
312019a81c14SSteve Longerbeam 		max_exp += ret;
31216146fde3SHugues Fruchet 		ret = 0;
312219a81c14SSteve Longerbeam 
312319a81c14SSteve Longerbeam 		if (ctrls->exposure->val < max_exp)
312419a81c14SSteve Longerbeam 			ret = ov5640_set_exposure(sensor, ctrls->exposure->val);
312519a81c14SSteve Longerbeam 	}
312619a81c14SSteve Longerbeam 
312719a81c14SSteve Longerbeam 	return ret;
312819a81c14SSteve Longerbeam }
312919a81c14SSteve Longerbeam 
31303cca8ef5SHugues Fruchet static int ov5640_set_ctrl_gain(struct ov5640_dev *sensor, bool auto_gain)
313119a81c14SSteve Longerbeam {
313219a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
313319a81c14SSteve Longerbeam 	int ret = 0;
313419a81c14SSteve Longerbeam 
313519a81c14SSteve Longerbeam 	if (ctrls->auto_gain->is_new) {
31363cca8ef5SHugues Fruchet 		ret = ov5640_set_autogain(sensor, auto_gain);
313719a81c14SSteve Longerbeam 		if (ret)
313819a81c14SSteve Longerbeam 			return ret;
313919a81c14SSteve Longerbeam 	}
314019a81c14SSteve Longerbeam 
31413cca8ef5SHugues Fruchet 	if (!auto_gain && ctrls->gain->is_new)
31423cca8ef5SHugues Fruchet 		ret = ov5640_set_gain(sensor, ctrls->gain->val);
314319a81c14SSteve Longerbeam 
314419a81c14SSteve Longerbeam 	return ret;
314519a81c14SSteve Longerbeam }
314619a81c14SSteve Longerbeam 
31479f6d7bacSChen-Yu Tsai static const char * const test_pattern_menu[] = {
31489f6d7bacSChen-Yu Tsai 	"Disabled",
31499f6d7bacSChen-Yu Tsai 	"Color bars",
3150bddc5cdfSChen-Yu Tsai 	"Color bars w/ rolling bar",
3151bddc5cdfSChen-Yu Tsai 	"Color squares",
3152bddc5cdfSChen-Yu Tsai 	"Color squares w/ rolling bar",
31539f6d7bacSChen-Yu Tsai };
31549f6d7bacSChen-Yu Tsai 
3155a0c29afbSChen-Yu Tsai #define OV5640_TEST_ENABLE		BIT(7)
3156a0c29afbSChen-Yu Tsai #define OV5640_TEST_ROLLING		BIT(6)	/* rolling horizontal bar */
3157a0c29afbSChen-Yu Tsai #define OV5640_TEST_TRANSPARENT		BIT(5)
3158a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE_BW		BIT(4)	/* black & white squares */
3159a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_STANDARD	(0 << 2)
3160a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_1	(1 << 2)
3161a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_HOR_CHANGE	(2 << 2)
3162a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_2	(3 << 2)
3163a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR			(0 << 0)
3164a0c29afbSChen-Yu Tsai #define OV5640_TEST_RANDOM		(1 << 0)
3165a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE		(2 << 0)
3166a0c29afbSChen-Yu Tsai #define OV5640_TEST_BLACK		(3 << 0)
3167a0c29afbSChen-Yu Tsai 
3168a0c29afbSChen-Yu Tsai static const u8 test_pattern_val[] = {
3169a0c29afbSChen-Yu Tsai 	0,
31702aff1fc3SChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_BAR_VERT_CHANGE_1 |
3171a0c29afbSChen-Yu Tsai 		OV5640_TEST_BAR,
3172bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_ROLLING |
3173bddc5cdfSChen-Yu Tsai 		OV5640_TEST_BAR_VERT_CHANGE_1 | OV5640_TEST_BAR,
3174bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_SQUARE,
3175bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_ROLLING | OV5640_TEST_SQUARE,
3176a0c29afbSChen-Yu Tsai };
3177a0c29afbSChen-Yu Tsai 
317819a81c14SSteve Longerbeam static int ov5640_set_ctrl_test_pattern(struct ov5640_dev *sensor, int value)
317919a81c14SSteve Longerbeam {
3180a0c29afbSChen-Yu Tsai 	return ov5640_write_reg(sensor, OV5640_REG_PRE_ISP_TEST_SET1,
3181a0c29afbSChen-Yu Tsai 				test_pattern_val[value]);
318219a81c14SSteve Longerbeam }
318319a81c14SSteve Longerbeam 
31841068fecaSMylène Josserand static int ov5640_set_ctrl_light_freq(struct ov5640_dev *sensor, int value)
31851068fecaSMylène Josserand {
31861068fecaSMylène Josserand 	int ret;
31871068fecaSMylène Josserand 
31881068fecaSMylène Josserand 	ret = ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL01, BIT(7),
31891068fecaSMylène Josserand 			     (value == V4L2_CID_POWER_LINE_FREQUENCY_AUTO) ?
31901068fecaSMylène Josserand 			     0 : BIT(7));
31911068fecaSMylène Josserand 	if (ret)
31921068fecaSMylène Josserand 		return ret;
31931068fecaSMylène Josserand 
31941068fecaSMylène Josserand 	return ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL00, BIT(2),
31951068fecaSMylène Josserand 			      (value == V4L2_CID_POWER_LINE_FREQUENCY_50HZ) ?
31961068fecaSMylène Josserand 			      BIT(2) : 0);
31971068fecaSMylène Josserand }
31981068fecaSMylène Josserand 
3199ce85705aSHugues Fruchet static int ov5640_set_ctrl_hflip(struct ov5640_dev *sensor, int value)
3200ce85705aSHugues Fruchet {
3201ce85705aSHugues Fruchet 	/*
3202c3f3ba3eSHugues Fruchet 	 * If sensor is mounted upside down, mirror logic is inversed.
3203c3f3ba3eSHugues Fruchet 	 *
3204ce85705aSHugues Fruchet 	 * Sensor is a BSI (Back Side Illuminated) one,
3205ce85705aSHugues Fruchet 	 * so image captured is physically mirrored.
3206ce85705aSHugues Fruchet 	 * This is why mirror logic is inversed in
3207ce85705aSHugues Fruchet 	 * order to cancel this mirror effect.
3208ce85705aSHugues Fruchet 	 */
3209ce85705aSHugues Fruchet 
3210ce85705aSHugues Fruchet 	/*
3211ce85705aSHugues Fruchet 	 * TIMING TC REG21:
3212ce85705aSHugues Fruchet 	 * - [2]:	ISP mirror
3213ce85705aSHugues Fruchet 	 * - [1]:	Sensor mirror
3214ce85705aSHugues Fruchet 	 */
3215ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
3216ce85705aSHugues Fruchet 			      BIT(2) | BIT(1),
3217c3f3ba3eSHugues Fruchet 			      (!(value ^ sensor->upside_down)) ?
3218c3f3ba3eSHugues Fruchet 			      (BIT(2) | BIT(1)) : 0);
3219ce85705aSHugues Fruchet }
3220ce85705aSHugues Fruchet 
3221ce85705aSHugues Fruchet static int ov5640_set_ctrl_vflip(struct ov5640_dev *sensor, int value)
3222ce85705aSHugues Fruchet {
3223c3f3ba3eSHugues Fruchet 	/* If sensor is mounted upside down, flip logic is inversed */
3224c3f3ba3eSHugues Fruchet 
3225ce85705aSHugues Fruchet 	/*
3226ce85705aSHugues Fruchet 	 * TIMING TC REG20:
3227ce85705aSHugues Fruchet 	 * - [2]:	ISP vflip
3228ce85705aSHugues Fruchet 	 * - [1]:	Sensor vflip
3229ce85705aSHugues Fruchet 	 */
3230ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20,
3231ce85705aSHugues Fruchet 			      BIT(2) | BIT(1),
3232c3f3ba3eSHugues Fruchet 			      (value ^ sensor->upside_down) ?
3233c3f3ba3eSHugues Fruchet 			      (BIT(2) | BIT(1)) : 0);
3234ce85705aSHugues Fruchet }
3235ce85705aSHugues Fruchet 
3236bce93b82SJacopo Mondi static int ov5640_set_ctrl_vblank(struct ov5640_dev *sensor, int value)
3237bce93b82SJacopo Mondi {
3238bce93b82SJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
3239bce93b82SJacopo Mondi 
3240bce93b82SJacopo Mondi 	/* Update the VTOT timing register value. */
3241bce93b82SJacopo Mondi 	return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS,
3242bce93b82SJacopo Mondi 				  mode->height + value);
3243bce93b82SJacopo Mondi }
3244bce93b82SJacopo Mondi 
324519a81c14SSteve Longerbeam static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
324619a81c14SSteve Longerbeam {
324719a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
324819a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
324919a81c14SSteve Longerbeam 	int val;
325019a81c14SSteve Longerbeam 
325119a81c14SSteve Longerbeam 	/* v4l2_ctrl_lock() locks our own mutex */
325219a81c14SSteve Longerbeam 
325319a81c14SSteve Longerbeam 	switch (ctrl->id) {
325419a81c14SSteve Longerbeam 	case V4L2_CID_AUTOGAIN:
325519a81c14SSteve Longerbeam 		val = ov5640_get_gain(sensor);
325619a81c14SSteve Longerbeam 		if (val < 0)
325719a81c14SSteve Longerbeam 			return val;
325819a81c14SSteve Longerbeam 		sensor->ctrls.gain->val = val;
325919a81c14SSteve Longerbeam 		break;
326019a81c14SSteve Longerbeam 	case V4L2_CID_EXPOSURE_AUTO:
326119a81c14SSteve Longerbeam 		val = ov5640_get_exposure(sensor);
326219a81c14SSteve Longerbeam 		if (val < 0)
326319a81c14SSteve Longerbeam 			return val;
326419a81c14SSteve Longerbeam 		sensor->ctrls.exposure->val = val;
326519a81c14SSteve Longerbeam 		break;
326619a81c14SSteve Longerbeam 	}
326719a81c14SSteve Longerbeam 
326819a81c14SSteve Longerbeam 	return 0;
326919a81c14SSteve Longerbeam }
327019a81c14SSteve Longerbeam 
327119a81c14SSteve Longerbeam static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl)
327219a81c14SSteve Longerbeam {
327319a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
327419a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
3275bce93b82SJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
3276bce93b82SJacopo Mondi 	const struct ov5640_timings *timings;
3277bce93b82SJacopo Mondi 	unsigned int exp_max;
327819a81c14SSteve Longerbeam 	int ret;
327919a81c14SSteve Longerbeam 
328019a81c14SSteve Longerbeam 	/* v4l2_ctrl_lock() locks our own mutex */
328119a81c14SSteve Longerbeam 
3282bce93b82SJacopo Mondi 	switch (ctrl->id) {
3283bce93b82SJacopo Mondi 	case V4L2_CID_VBLANK:
3284bce93b82SJacopo Mondi 		/* Update the exposure range to the newly programmed vblank. */
3285bce93b82SJacopo Mondi 		timings = ov5640_timings(sensor, mode);
3286bce93b82SJacopo Mondi 		exp_max = mode->height + ctrl->val - 4;
3287bce93b82SJacopo Mondi 		__v4l2_ctrl_modify_range(sensor->ctrls.exposure,
3288bce93b82SJacopo Mondi 					 sensor->ctrls.exposure->minimum,
3289bce93b82SJacopo Mondi 					 exp_max, sensor->ctrls.exposure->step,
3290bce93b82SJacopo Mondi 					 timings->vblank_def);
3291bce93b82SJacopo Mondi 		break;
3292bce93b82SJacopo Mondi 	}
3293bce93b82SJacopo Mondi 
329419a81c14SSteve Longerbeam 	/*
329519a81c14SSteve Longerbeam 	 * If the device is not powered up by the host driver do
329619a81c14SSteve Longerbeam 	 * not apply any controls to H/W at this time. Instead
329719a81c14SSteve Longerbeam 	 * the controls will be restored right after power-up.
329819a81c14SSteve Longerbeam 	 */
329919a81c14SSteve Longerbeam 	if (sensor->power_count == 0)
330019a81c14SSteve Longerbeam 		return 0;
330119a81c14SSteve Longerbeam 
330219a81c14SSteve Longerbeam 	switch (ctrl->id) {
330319a81c14SSteve Longerbeam 	case V4L2_CID_AUTOGAIN:
330419a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_gain(sensor, ctrl->val);
330519a81c14SSteve Longerbeam 		break;
330619a81c14SSteve Longerbeam 	case V4L2_CID_EXPOSURE_AUTO:
330719a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_exposure(sensor, ctrl->val);
330819a81c14SSteve Longerbeam 		break;
330919a81c14SSteve Longerbeam 	case V4L2_CID_AUTO_WHITE_BALANCE:
331019a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_white_balance(sensor, ctrl->val);
331119a81c14SSteve Longerbeam 		break;
331219a81c14SSteve Longerbeam 	case V4L2_CID_HUE:
331319a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_hue(sensor, ctrl->val);
331419a81c14SSteve Longerbeam 		break;
331519a81c14SSteve Longerbeam 	case V4L2_CID_CONTRAST:
331619a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_contrast(sensor, ctrl->val);
331719a81c14SSteve Longerbeam 		break;
331819a81c14SSteve Longerbeam 	case V4L2_CID_SATURATION:
331919a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_saturation(sensor, ctrl->val);
332019a81c14SSteve Longerbeam 		break;
332119a81c14SSteve Longerbeam 	case V4L2_CID_TEST_PATTERN:
332219a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_test_pattern(sensor, ctrl->val);
332319a81c14SSteve Longerbeam 		break;
33241068fecaSMylène Josserand 	case V4L2_CID_POWER_LINE_FREQUENCY:
33251068fecaSMylène Josserand 		ret = ov5640_set_ctrl_light_freq(sensor, ctrl->val);
33261068fecaSMylène Josserand 		break;
3327ce85705aSHugues Fruchet 	case V4L2_CID_HFLIP:
3328ce85705aSHugues Fruchet 		ret = ov5640_set_ctrl_hflip(sensor, ctrl->val);
3329ce85705aSHugues Fruchet 		break;
3330ce85705aSHugues Fruchet 	case V4L2_CID_VFLIP:
3331ce85705aSHugues Fruchet 		ret = ov5640_set_ctrl_vflip(sensor, ctrl->val);
3332ce85705aSHugues Fruchet 		break;
3333bce93b82SJacopo Mondi 	case V4L2_CID_VBLANK:
3334bce93b82SJacopo Mondi 		ret = ov5640_set_ctrl_vblank(sensor, ctrl->val);
3335bce93b82SJacopo Mondi 		break;
333619a81c14SSteve Longerbeam 	default:
333719a81c14SSteve Longerbeam 		ret = -EINVAL;
333819a81c14SSteve Longerbeam 		break;
333919a81c14SSteve Longerbeam 	}
334019a81c14SSteve Longerbeam 
334119a81c14SSteve Longerbeam 	return ret;
334219a81c14SSteve Longerbeam }
334319a81c14SSteve Longerbeam 
334419a81c14SSteve Longerbeam static const struct v4l2_ctrl_ops ov5640_ctrl_ops = {
334519a81c14SSteve Longerbeam 	.g_volatile_ctrl = ov5640_g_volatile_ctrl,
334619a81c14SSteve Longerbeam 	.s_ctrl = ov5640_s_ctrl,
334719a81c14SSteve Longerbeam };
334819a81c14SSteve Longerbeam 
334919a81c14SSteve Longerbeam static int ov5640_init_controls(struct ov5640_dev *sensor)
335019a81c14SSteve Longerbeam {
335122845bf2SJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
335219a81c14SSteve Longerbeam 	const struct v4l2_ctrl_ops *ops = &ov5640_ctrl_ops;
335319a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
335419a81c14SSteve Longerbeam 	struct v4l2_ctrl_handler *hdl = &ctrls->handler;
33551066fc1cSJacopo Mondi 	struct v4l2_fwnode_device_properties props;
335632979f67SJacopo Mondi 	const struct ov5640_timings *timings;
3357bce93b82SJacopo Mondi 	unsigned int max_vblank;
335832979f67SJacopo Mondi 	unsigned int hblank;
335919a81c14SSteve Longerbeam 	int ret;
336019a81c14SSteve Longerbeam 
336119a81c14SSteve Longerbeam 	v4l2_ctrl_handler_init(hdl, 32);
336219a81c14SSteve Longerbeam 
336319a81c14SSteve Longerbeam 	/* we can use our own mutex for the ctrl lock */
336419a81c14SSteve Longerbeam 	hdl->lock = &sensor->lock;
336519a81c14SSteve Longerbeam 
3366cc196e48SBenoit Parrot 	/* Clock related controls */
3367cc196e48SBenoit Parrot 	ctrls->pixel_rate = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE,
336822845bf2SJacopo Mondi 			      ov5640_pixel_rates[OV5640_NUM_PIXEL_RATES - 1],
336922845bf2SJacopo Mondi 			      ov5640_pixel_rates[0], 1,
337022845bf2SJacopo Mondi 			      ov5640_pixel_rates[mode->pixel_rate]);
3371cc196e48SBenoit Parrot 
33727a3b8d4bSJacopo Mondi 	ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops,
33737a3b8d4bSJacopo Mondi 					V4L2_CID_LINK_FREQ,
33747a3b8d4bSJacopo Mondi 					ARRAY_SIZE(ov5640_csi2_link_freqs) - 1,
33757a3b8d4bSJacopo Mondi 					OV5640_DEFAULT_LINK_FREQ,
33767a3b8d4bSJacopo Mondi 					ov5640_csi2_link_freqs);
33777a3b8d4bSJacopo Mondi 
337832979f67SJacopo Mondi 	timings = ov5640_timings(sensor, mode);
337932979f67SJacopo Mondi 	hblank = timings->htot - mode->width;
338032979f67SJacopo Mondi 	ctrls->hblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HBLANK, hblank,
338132979f67SJacopo Mondi 					  hblank, 1, hblank);
338232979f67SJacopo Mondi 
3383bce93b82SJacopo Mondi 	max_vblank = OV5640_MAX_VTS - mode->height;
3384bce93b82SJacopo Mondi 	ctrls->vblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VBLANK,
3385bce93b82SJacopo Mondi 					  OV5640_MIN_VBLANK, max_vblank,
3386bce93b82SJacopo Mondi 					  1, timings->vblank_def);
3387bce93b82SJacopo Mondi 
338819a81c14SSteve Longerbeam 	/* Auto/manual white balance */
338919a81c14SSteve Longerbeam 	ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops,
339019a81c14SSteve Longerbeam 					   V4L2_CID_AUTO_WHITE_BALANCE,
339119a81c14SSteve Longerbeam 					   0, 1, 1, 1);
339219a81c14SSteve Longerbeam 	ctrls->blue_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BLUE_BALANCE,
339319a81c14SSteve Longerbeam 						0, 4095, 1, 0);
339419a81c14SSteve Longerbeam 	ctrls->red_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_RED_BALANCE,
339519a81c14SSteve Longerbeam 					       0, 4095, 1, 0);
339619a81c14SSteve Longerbeam 	/* Auto/manual exposure */
339719a81c14SSteve Longerbeam 	ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops,
339819a81c14SSteve Longerbeam 						 V4L2_CID_EXPOSURE_AUTO,
339919a81c14SSteve Longerbeam 						 V4L2_EXPOSURE_MANUAL, 0,
340019a81c14SSteve Longerbeam 						 V4L2_EXPOSURE_AUTO);
340119a81c14SSteve Longerbeam 	ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
340219a81c14SSteve Longerbeam 					    0, 65535, 1, 0);
340319a81c14SSteve Longerbeam 	/* Auto/manual gain */
340419a81c14SSteve Longerbeam 	ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN,
340519a81c14SSteve Longerbeam 					     0, 1, 1, 1);
340619a81c14SSteve Longerbeam 	ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN,
340719a81c14SSteve Longerbeam 					0, 1023, 1, 0);
340819a81c14SSteve Longerbeam 
340919a81c14SSteve Longerbeam 	ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION,
341019a81c14SSteve Longerbeam 					      0, 255, 1, 64);
341119a81c14SSteve Longerbeam 	ctrls->hue = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HUE,
341219a81c14SSteve Longerbeam 				       0, 359, 1, 0);
341319a81c14SSteve Longerbeam 	ctrls->contrast = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST,
341419a81c14SSteve Longerbeam 					    0, 255, 1, 0);
341519a81c14SSteve Longerbeam 	ctrls->test_pattern =
341619a81c14SSteve Longerbeam 		v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN,
341719a81c14SSteve Longerbeam 					     ARRAY_SIZE(test_pattern_menu) - 1,
341819a81c14SSteve Longerbeam 					     0, 0, test_pattern_menu);
3419ce85705aSHugues Fruchet 	ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP,
3420ce85705aSHugues Fruchet 					 0, 1, 1, 0);
3421ce85705aSHugues Fruchet 	ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP,
3422ce85705aSHugues Fruchet 					 0, 1, 1, 0);
342319a81c14SSteve Longerbeam 
34241068fecaSMylène Josserand 	ctrls->light_freq =
34251068fecaSMylène Josserand 		v4l2_ctrl_new_std_menu(hdl, ops,
34261068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY,
34271068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
34281068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
34291068fecaSMylène Josserand 
343019a81c14SSteve Longerbeam 	if (hdl->error) {
343119a81c14SSteve Longerbeam 		ret = hdl->error;
343219a81c14SSteve Longerbeam 		goto free_ctrls;
343319a81c14SSteve Longerbeam 	}
343419a81c14SSteve Longerbeam 
34351066fc1cSJacopo Mondi 	ret = v4l2_fwnode_device_parse(&sensor->i2c_client->dev, &props);
34361066fc1cSJacopo Mondi 	if (ret)
34371066fc1cSJacopo Mondi 		goto free_ctrls;
34381066fc1cSJacopo Mondi 
34391066fc1cSJacopo Mondi 	if (props.rotation == 180)
34401066fc1cSJacopo Mondi 		sensor->upside_down = true;
34411066fc1cSJacopo Mondi 
34421066fc1cSJacopo Mondi 	ret = v4l2_ctrl_new_fwnode_properties(hdl, ops, &props);
34431066fc1cSJacopo Mondi 	if (ret)
34441066fc1cSJacopo Mondi 		goto free_ctrls;
34451066fc1cSJacopo Mondi 
3446cc196e48SBenoit Parrot 	ctrls->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY;
34477a3b8d4bSJacopo Mondi 	ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
344832979f67SJacopo Mondi 	ctrls->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
344919a81c14SSteve Longerbeam 	ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE;
345019a81c14SSteve Longerbeam 	ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE;
345119a81c14SSteve Longerbeam 
345219a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false);
345319a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(2, &ctrls->auto_gain, 0, true);
345419a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(2, &ctrls->auto_exp, 1, true);
345519a81c14SSteve Longerbeam 
345619a81c14SSteve Longerbeam 	sensor->sd.ctrl_handler = hdl;
345719a81c14SSteve Longerbeam 	return 0;
345819a81c14SSteve Longerbeam 
345919a81c14SSteve Longerbeam free_ctrls:
346019a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(hdl);
346119a81c14SSteve Longerbeam 	return ret;
346219a81c14SSteve Longerbeam }
346319a81c14SSteve Longerbeam 
346419a81c14SSteve Longerbeam static int ov5640_enum_frame_size(struct v4l2_subdev *sd,
34650d346d2aSTomi Valkeinen 				  struct v4l2_subdev_state *sd_state,
346619a81c14SSteve Longerbeam 				  struct v4l2_subdev_frame_size_enum *fse)
346719a81c14SSteve Longerbeam {
346819a81c14SSteve Longerbeam 	if (fse->pad != 0)
346919a81c14SSteve Longerbeam 		return -EINVAL;
347019a81c14SSteve Longerbeam 	if (fse->index >= OV5640_NUM_MODES)
347119a81c14SSteve Longerbeam 		return -EINVAL;
347219a81c14SSteve Longerbeam 
34735113d5b3SJacopo Mondi 	fse->min_width = ov5640_mode_data[fse->index].width;
347441d8d7f5SHugues Fruchet 	fse->max_width = fse->min_width;
34755113d5b3SJacopo Mondi 	fse->min_height = ov5640_mode_data[fse->index].height;
347641d8d7f5SHugues Fruchet 	fse->max_height = fse->min_height;
347719a81c14SSteve Longerbeam 
347819a81c14SSteve Longerbeam 	return 0;
347919a81c14SSteve Longerbeam }
348019a81c14SSteve Longerbeam 
348119a81c14SSteve Longerbeam static int ov5640_enum_frame_interval(
348219a81c14SSteve Longerbeam 	struct v4l2_subdev *sd,
34830d346d2aSTomi Valkeinen 	struct v4l2_subdev_state *sd_state,
348419a81c14SSteve Longerbeam 	struct v4l2_subdev_frame_interval_enum *fie)
348519a81c14SSteve Longerbeam {
348619a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
348719a81c14SSteve Longerbeam 	struct v4l2_fract tpf;
348819a81c14SSteve Longerbeam 	int ret;
348919a81c14SSteve Longerbeam 
349019a81c14SSteve Longerbeam 	if (fie->pad != 0)
349119a81c14SSteve Longerbeam 		return -EINVAL;
349219a81c14SSteve Longerbeam 	if (fie->index >= OV5640_NUM_FRAMERATES)
349319a81c14SSteve Longerbeam 		return -EINVAL;
349419a81c14SSteve Longerbeam 
349519a81c14SSteve Longerbeam 	tpf.numerator = 1;
349619a81c14SSteve Longerbeam 	tpf.denominator = ov5640_framerates[fie->index];
349719a81c14SSteve Longerbeam 
349819a81c14SSteve Longerbeam 	ret = ov5640_try_frame_interval(sensor, &tpf,
349919a81c14SSteve Longerbeam 					fie->width, fie->height);
350019a81c14SSteve Longerbeam 	if (ret < 0)
350119a81c14SSteve Longerbeam 		return -EINVAL;
350219a81c14SSteve Longerbeam 
350319a81c14SSteve Longerbeam 	fie->interval = tpf;
350419a81c14SSteve Longerbeam 	return 0;
350519a81c14SSteve Longerbeam }
350619a81c14SSteve Longerbeam 
350719a81c14SSteve Longerbeam static int ov5640_g_frame_interval(struct v4l2_subdev *sd,
350819a81c14SSteve Longerbeam 				   struct v4l2_subdev_frame_interval *fi)
350919a81c14SSteve Longerbeam {
351019a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
351119a81c14SSteve Longerbeam 
351219a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
351319a81c14SSteve Longerbeam 	fi->interval = sensor->frame_interval;
351419a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
351519a81c14SSteve Longerbeam 
351619a81c14SSteve Longerbeam 	return 0;
351719a81c14SSteve Longerbeam }
351819a81c14SSteve Longerbeam 
351919a81c14SSteve Longerbeam static int ov5640_s_frame_interval(struct v4l2_subdev *sd,
352019a81c14SSteve Longerbeam 				   struct v4l2_subdev_frame_interval *fi)
352119a81c14SSteve Longerbeam {
352219a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
352319a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
352419a81c14SSteve Longerbeam 	int frame_rate, ret = 0;
352519a81c14SSteve Longerbeam 
352619a81c14SSteve Longerbeam 	if (fi->pad != 0)
352719a81c14SSteve Longerbeam 		return -EINVAL;
352819a81c14SSteve Longerbeam 
352919a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
353019a81c14SSteve Longerbeam 
353119a81c14SSteve Longerbeam 	if (sensor->streaming) {
353219a81c14SSteve Longerbeam 		ret = -EBUSY;
353319a81c14SSteve Longerbeam 		goto out;
353419a81c14SSteve Longerbeam 	}
353519a81c14SSteve Longerbeam 
353619a81c14SSteve Longerbeam 	mode = sensor->current_mode;
353719a81c14SSteve Longerbeam 
353819a81c14SSteve Longerbeam 	frame_rate = ov5640_try_frame_interval(sensor, &fi->interval,
35395113d5b3SJacopo Mondi 					       mode->width,
35405113d5b3SJacopo Mondi 					       mode->height);
3541e823fb16SMaxime Ripard 	if (frame_rate < 0) {
3542e823fb16SMaxime Ripard 		/* Always return a valid frame interval value */
3543e823fb16SMaxime Ripard 		fi->interval = sensor->frame_interval;
3544e823fb16SMaxime Ripard 		goto out;
3545e823fb16SMaxime Ripard 	}
354619a81c14SSteve Longerbeam 
3547b6ae5022SJacopo Mondi 	mode = ov5640_find_mode(sensor, mode->width, mode->height, true);
35483c4a7372SHugues Fruchet 	if (!mode) {
35493c4a7372SHugues Fruchet 		ret = -EINVAL;
35503c4a7372SHugues Fruchet 		goto out;
35513c4a7372SHugues Fruchet 	}
35523c4a7372SHugues Fruchet 
3553b6ae5022SJacopo Mondi 	if (ov5640_framerates[frame_rate] > ov5640_framerates[mode->max_fps]) {
3554b6ae5022SJacopo Mondi 		ret = -EINVAL;
3555b6ae5022SJacopo Mondi 		goto out;
3556b6ae5022SJacopo Mondi 	}
3557b6ae5022SJacopo Mondi 
35580929983eSHugues Fruchet 	if (mode != sensor->current_mode ||
35590929983eSHugues Fruchet 	    frame_rate != sensor->current_fr) {
35600929983eSHugues Fruchet 		sensor->current_fr = frame_rate;
35610929983eSHugues Fruchet 		sensor->frame_interval = fi->interval;
35623c4a7372SHugues Fruchet 		sensor->current_mode = mode;
356319a81c14SSteve Longerbeam 		sensor->pending_mode_change = true;
3564cc196e48SBenoit Parrot 
356519f2e3e6SHugues Fruchet 		ov5640_update_pixel_rate(sensor);
35666949d864SHugues Fruchet 	}
356719a81c14SSteve Longerbeam out:
356819a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
356919a81c14SSteve Longerbeam 	return ret;
357019a81c14SSteve Longerbeam }
357119a81c14SSteve Longerbeam 
357219a81c14SSteve Longerbeam static int ov5640_enum_mbus_code(struct v4l2_subdev *sd,
35730d346d2aSTomi Valkeinen 				 struct v4l2_subdev_state *sd_state,
357419a81c14SSteve Longerbeam 				 struct v4l2_subdev_mbus_code_enum *code)
357519a81c14SSteve Longerbeam {
357619a81c14SSteve Longerbeam 	if (code->pad != 0)
357719a81c14SSteve Longerbeam 		return -EINVAL;
3578e3ee691dSHugues Fruchet 	if (code->index >= ARRAY_SIZE(ov5640_formats))
357919a81c14SSteve Longerbeam 		return -EINVAL;
358019a81c14SSteve Longerbeam 
3581e3ee691dSHugues Fruchet 	code->code = ov5640_formats[code->index].code;
358219a81c14SSteve Longerbeam 	return 0;
358319a81c14SSteve Longerbeam }
358419a81c14SSteve Longerbeam 
358519a81c14SSteve Longerbeam static int ov5640_s_stream(struct v4l2_subdev *sd, int enable)
358619a81c14SSteve Longerbeam {
358719a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
358819a81c14SSteve Longerbeam 	int ret = 0;
358919a81c14SSteve Longerbeam 
359019a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
359119a81c14SSteve Longerbeam 
359219a81c14SSteve Longerbeam 	if (sensor->streaming == !enable) {
359319a81c14SSteve Longerbeam 		if (enable && sensor->pending_mode_change) {
3594985cdcb0SHugues Fruchet 			ret = ov5640_set_mode(sensor);
359519a81c14SSteve Longerbeam 			if (ret)
359619a81c14SSteve Longerbeam 				goto out;
3597fb98e29fSHugues Fruchet 		}
3598e3ee691dSHugues Fruchet 
3599fb98e29fSHugues Fruchet 		if (enable && sensor->pending_fmt_change) {
3600e3ee691dSHugues Fruchet 			ret = ov5640_set_framefmt(sensor, &sensor->fmt);
3601e3ee691dSHugues Fruchet 			if (ret)
3602e3ee691dSHugues Fruchet 				goto out;
3603fb98e29fSHugues Fruchet 			sensor->pending_fmt_change = false;
360419a81c14SSteve Longerbeam 		}
360519a81c14SSteve Longerbeam 
36068e823f5cSJacopo Mondi 		if (ov5640_is_csi2(sensor))
3607f22996dbSHugues Fruchet 			ret = ov5640_set_stream_mipi(sensor, enable);
3608f22996dbSHugues Fruchet 		else
3609f22996dbSHugues Fruchet 			ret = ov5640_set_stream_dvp(sensor, enable);
3610f22996dbSHugues Fruchet 
361119a81c14SSteve Longerbeam 		if (!ret)
361219a81c14SSteve Longerbeam 			sensor->streaming = enable;
361319a81c14SSteve Longerbeam 	}
361419a81c14SSteve Longerbeam out:
361519a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
361619a81c14SSteve Longerbeam 	return ret;
361719a81c14SSteve Longerbeam }
361819a81c14SSteve Longerbeam 
361990b0f355SJacopo Mondi static int ov5640_init_cfg(struct v4l2_subdev *sd,
362090b0f355SJacopo Mondi 			   struct v4l2_subdev_state *state)
362190b0f355SJacopo Mondi {
362290b0f355SJacopo Mondi 	struct v4l2_mbus_framefmt *fmt =
362390b0f355SJacopo Mondi 				v4l2_subdev_get_try_format(sd, state, 0);
362466ed85ebSJacopo Mondi 	struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, state, 0);
362590b0f355SJacopo Mondi 
362690b0f355SJacopo Mondi 	*fmt = ov5640_default_fmt;
362790b0f355SJacopo Mondi 
362866ed85ebSJacopo Mondi 	crop->left = OV5640_PIXEL_ARRAY_LEFT;
362966ed85ebSJacopo Mondi 	crop->top = OV5640_PIXEL_ARRAY_TOP;
363066ed85ebSJacopo Mondi 	crop->width = OV5640_PIXEL_ARRAY_WIDTH;
363166ed85ebSJacopo Mondi 	crop->height = OV5640_PIXEL_ARRAY_HEIGHT;
363266ed85ebSJacopo Mondi 
363390b0f355SJacopo Mondi 	return 0;
363490b0f355SJacopo Mondi }
363590b0f355SJacopo Mondi 
363619a81c14SSteve Longerbeam static const struct v4l2_subdev_core_ops ov5640_core_ops = {
363719a81c14SSteve Longerbeam 	.s_power = ov5640_s_power,
36382d18fbc5SAkinobu Mita 	.log_status = v4l2_ctrl_subdev_log_status,
36392d18fbc5SAkinobu Mita 	.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
36402d18fbc5SAkinobu Mita 	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
364119a81c14SSteve Longerbeam };
364219a81c14SSteve Longerbeam 
364319a81c14SSteve Longerbeam static const struct v4l2_subdev_video_ops ov5640_video_ops = {
364419a81c14SSteve Longerbeam 	.g_frame_interval = ov5640_g_frame_interval,
364519a81c14SSteve Longerbeam 	.s_frame_interval = ov5640_s_frame_interval,
364619a81c14SSteve Longerbeam 	.s_stream = ov5640_s_stream,
364719a81c14SSteve Longerbeam };
364819a81c14SSteve Longerbeam 
364919a81c14SSteve Longerbeam static const struct v4l2_subdev_pad_ops ov5640_pad_ops = {
365090b0f355SJacopo Mondi 	.init_cfg = ov5640_init_cfg,
365119a81c14SSteve Longerbeam 	.enum_mbus_code = ov5640_enum_mbus_code,
365219a81c14SSteve Longerbeam 	.get_fmt = ov5640_get_fmt,
365319a81c14SSteve Longerbeam 	.set_fmt = ov5640_set_fmt,
365466ed85ebSJacopo Mondi 	.get_selection = ov5640_get_selection,
365519a81c14SSteve Longerbeam 	.enum_frame_size = ov5640_enum_frame_size,
365619a81c14SSteve Longerbeam 	.enum_frame_interval = ov5640_enum_frame_interval,
365719a81c14SSteve Longerbeam };
365819a81c14SSteve Longerbeam 
365919a81c14SSteve Longerbeam static const struct v4l2_subdev_ops ov5640_subdev_ops = {
366019a81c14SSteve Longerbeam 	.core = &ov5640_core_ops,
366119a81c14SSteve Longerbeam 	.video = &ov5640_video_ops,
366219a81c14SSteve Longerbeam 	.pad = &ov5640_pad_ops,
366319a81c14SSteve Longerbeam };
366419a81c14SSteve Longerbeam 
366519a81c14SSteve Longerbeam static int ov5640_get_regulators(struct ov5640_dev *sensor)
366619a81c14SSteve Longerbeam {
366719a81c14SSteve Longerbeam 	int i;
366819a81c14SSteve Longerbeam 
366919a81c14SSteve Longerbeam 	for (i = 0; i < OV5640_NUM_SUPPLIES; i++)
367019a81c14SSteve Longerbeam 		sensor->supplies[i].supply = ov5640_supply_name[i];
367119a81c14SSteve Longerbeam 
367219a81c14SSteve Longerbeam 	return devm_regulator_bulk_get(&sensor->i2c_client->dev,
367319a81c14SSteve Longerbeam 				       OV5640_NUM_SUPPLIES,
367419a81c14SSteve Longerbeam 				       sensor->supplies);
367519a81c14SSteve Longerbeam }
367619a81c14SSteve Longerbeam 
36770f7acb52SHugues Fruchet static int ov5640_check_chip_id(struct ov5640_dev *sensor)
36780f7acb52SHugues Fruchet {
36790f7acb52SHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
36800f7acb52SHugues Fruchet 	int ret = 0;
36810f7acb52SHugues Fruchet 	u16 chip_id;
36820f7acb52SHugues Fruchet 
36830f7acb52SHugues Fruchet 	ret = ov5640_set_power_on(sensor);
36840f7acb52SHugues Fruchet 	if (ret)
36850f7acb52SHugues Fruchet 		return ret;
36860f7acb52SHugues Fruchet 
36870f7acb52SHugues Fruchet 	ret = ov5640_read_reg16(sensor, OV5640_REG_CHIP_ID, &chip_id);
36880f7acb52SHugues Fruchet 	if (ret) {
36890f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to read chip identifier\n",
36900f7acb52SHugues Fruchet 			__func__);
36910f7acb52SHugues Fruchet 		goto power_off;
36920f7acb52SHugues Fruchet 	}
36930f7acb52SHugues Fruchet 
36940f7acb52SHugues Fruchet 	if (chip_id != 0x5640) {
36950f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: wrong chip identifier, expected 0x5640, got 0x%x\n",
36960f7acb52SHugues Fruchet 			__func__, chip_id);
36970f7acb52SHugues Fruchet 		ret = -ENXIO;
36980f7acb52SHugues Fruchet 	}
36990f7acb52SHugues Fruchet 
37000f7acb52SHugues Fruchet power_off:
37010f7acb52SHugues Fruchet 	ov5640_set_power_off(sensor);
37020f7acb52SHugues Fruchet 	return ret;
37030f7acb52SHugues Fruchet }
37040f7acb52SHugues Fruchet 
3705e6714993SKieran Bingham static int ov5640_probe(struct i2c_client *client)
370619a81c14SSteve Longerbeam {
370719a81c14SSteve Longerbeam 	struct device *dev = &client->dev;
370819a81c14SSteve Longerbeam 	struct fwnode_handle *endpoint;
370919a81c14SSteve Longerbeam 	struct ov5640_dev *sensor;
371019a81c14SSteve Longerbeam 	int ret;
371119a81c14SSteve Longerbeam 
371219a81c14SSteve Longerbeam 	sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
371319a81c14SSteve Longerbeam 	if (!sensor)
371419a81c14SSteve Longerbeam 		return -ENOMEM;
371519a81c14SSteve Longerbeam 
371619a81c14SSteve Longerbeam 	sensor->i2c_client = client;
3717fb98e29fSHugues Fruchet 
3718fb98e29fSHugues Fruchet 	/*
3719fb98e29fSHugues Fruchet 	 * default init sequence initialize sensor to
3720fb98e29fSHugues Fruchet 	 * YUV422 UYVY VGA@30fps
3721fb98e29fSHugues Fruchet 	 */
372290b0f355SJacopo Mondi 	sensor->fmt = ov5640_default_fmt;
372319a81c14SSteve Longerbeam 	sensor->frame_interval.numerator = 1;
372419a81c14SSteve Longerbeam 	sensor->frame_interval.denominator = ov5640_framerates[OV5640_30_FPS];
372519a81c14SSteve Longerbeam 	sensor->current_fr = OV5640_30_FPS;
372619a81c14SSteve Longerbeam 	sensor->current_mode =
3727086c25f8SMaxime Ripard 		&ov5640_mode_data[OV5640_MODE_VGA_640_480];
3728985cdcb0SHugues Fruchet 	sensor->last_mode = sensor->current_mode;
37293c28588fSJacopo Mondi 	sensor->current_link_freq = OV5640_DEFAULT_LINK_FREQ;
373019a81c14SSteve Longerbeam 
373119a81c14SSteve Longerbeam 	sensor->ae_target = 52;
373219a81c14SSteve Longerbeam 
3733ce96bcf5SSakari Ailus 	endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev),
3734ce96bcf5SSakari Ailus 						  NULL);
373519a81c14SSteve Longerbeam 	if (!endpoint) {
373619a81c14SSteve Longerbeam 		dev_err(dev, "endpoint node not found\n");
373719a81c14SSteve Longerbeam 		return -EINVAL;
373819a81c14SSteve Longerbeam 	}
373919a81c14SSteve Longerbeam 
374019a81c14SSteve Longerbeam 	ret = v4l2_fwnode_endpoint_parse(endpoint, &sensor->ep);
374119a81c14SSteve Longerbeam 	fwnode_handle_put(endpoint);
374219a81c14SSteve Longerbeam 	if (ret) {
374319a81c14SSteve Longerbeam 		dev_err(dev, "Could not parse endpoint\n");
374419a81c14SSteve Longerbeam 		return ret;
374519a81c14SSteve Longerbeam 	}
374619a81c14SSteve Longerbeam 
37472c61e48dSLad Prabhakar 	if (sensor->ep.bus_type != V4L2_MBUS_PARALLEL &&
37482c61e48dSLad Prabhakar 	    sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY &&
37492c61e48dSLad Prabhakar 	    sensor->ep.bus_type != V4L2_MBUS_BT656) {
37502c61e48dSLad Prabhakar 		dev_err(dev, "Unsupported bus type %d\n", sensor->ep.bus_type);
37512c61e48dSLad Prabhakar 		return -EINVAL;
37522c61e48dSLad Prabhakar 	}
37532c61e48dSLad Prabhakar 
375419a81c14SSteve Longerbeam 	/* get system clock (xclk) */
375519a81c14SSteve Longerbeam 	sensor->xclk = devm_clk_get(dev, "xclk");
375619a81c14SSteve Longerbeam 	if (IS_ERR(sensor->xclk)) {
375719a81c14SSteve Longerbeam 		dev_err(dev, "failed to get xclk\n");
375819a81c14SSteve Longerbeam 		return PTR_ERR(sensor->xclk);
375919a81c14SSteve Longerbeam 	}
376019a81c14SSteve Longerbeam 
376119a81c14SSteve Longerbeam 	sensor->xclk_freq = clk_get_rate(sensor->xclk);
376219a81c14SSteve Longerbeam 	if (sensor->xclk_freq < OV5640_XCLK_MIN ||
376319a81c14SSteve Longerbeam 	    sensor->xclk_freq > OV5640_XCLK_MAX) {
376419a81c14SSteve Longerbeam 		dev_err(dev, "xclk frequency out of range: %d Hz\n",
376519a81c14SSteve Longerbeam 			sensor->xclk_freq);
376619a81c14SSteve Longerbeam 		return -EINVAL;
376719a81c14SSteve Longerbeam 	}
376819a81c14SSteve Longerbeam 
376919a81c14SSteve Longerbeam 	/* request optional power down pin */
377019a81c14SSteve Longerbeam 	sensor->pwdn_gpio = devm_gpiod_get_optional(dev, "powerdown",
377119a81c14SSteve Longerbeam 						    GPIOD_OUT_HIGH);
37728791a102SFabio Estevam 	if (IS_ERR(sensor->pwdn_gpio))
37738791a102SFabio Estevam 		return PTR_ERR(sensor->pwdn_gpio);
37748791a102SFabio Estevam 
377519a81c14SSteve Longerbeam 	/* request optional reset pin */
377619a81c14SSteve Longerbeam 	sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset",
377719a81c14SSteve Longerbeam 						     GPIOD_OUT_HIGH);
37788791a102SFabio Estevam 	if (IS_ERR(sensor->reset_gpio))
37798791a102SFabio Estevam 		return PTR_ERR(sensor->reset_gpio);
378019a81c14SSteve Longerbeam 
378119a81c14SSteve Longerbeam 	v4l2_i2c_subdev_init(&sensor->sd, client, &ov5640_subdev_ops);
378219a81c14SSteve Longerbeam 
37832d18fbc5SAkinobu Mita 	sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
37842d18fbc5SAkinobu Mita 			    V4L2_SUBDEV_FL_HAS_EVENTS;
378519a81c14SSteve Longerbeam 	sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
378619a81c14SSteve Longerbeam 	sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
378719a81c14SSteve Longerbeam 	ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
378819a81c14SSteve Longerbeam 	if (ret)
378919a81c14SSteve Longerbeam 		return ret;
379019a81c14SSteve Longerbeam 
379119a81c14SSteve Longerbeam 	ret = ov5640_get_regulators(sensor);
379219a81c14SSteve Longerbeam 	if (ret)
379319a81c14SSteve Longerbeam 		return ret;
379419a81c14SSteve Longerbeam 
379519a81c14SSteve Longerbeam 	mutex_init(&sensor->lock);
379619a81c14SSteve Longerbeam 
37970f7acb52SHugues Fruchet 	ret = ov5640_check_chip_id(sensor);
37980f7acb52SHugues Fruchet 	if (ret)
37990f7acb52SHugues Fruchet 		goto entity_cleanup;
38000f7acb52SHugues Fruchet 
380119a81c14SSteve Longerbeam 	ret = ov5640_init_controls(sensor);
380219a81c14SSteve Longerbeam 	if (ret)
380319a81c14SSteve Longerbeam 		goto entity_cleanup;
380419a81c14SSteve Longerbeam 
380515786f7bSSakari Ailus 	ret = v4l2_async_register_subdev_sensor(&sensor->sd);
380619a81c14SSteve Longerbeam 	if (ret)
380719a81c14SSteve Longerbeam 		goto free_ctrls;
380819a81c14SSteve Longerbeam 
380919a81c14SSteve Longerbeam 	return 0;
381019a81c14SSteve Longerbeam 
381119a81c14SSteve Longerbeam free_ctrls:
381219a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
381319a81c14SSteve Longerbeam entity_cleanup:
381419a81c14SSteve Longerbeam 	media_entity_cleanup(&sensor->sd.entity);
3815bfcba38dSTomi Valkeinen 	mutex_destroy(&sensor->lock);
381619a81c14SSteve Longerbeam 	return ret;
381719a81c14SSteve Longerbeam }
381819a81c14SSteve Longerbeam 
381919a81c14SSteve Longerbeam static int ov5640_remove(struct i2c_client *client)
382019a81c14SSteve Longerbeam {
382119a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
382219a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
382319a81c14SSteve Longerbeam 
382419a81c14SSteve Longerbeam 	v4l2_async_unregister_subdev(&sensor->sd);
382519a81c14SSteve Longerbeam 	media_entity_cleanup(&sensor->sd.entity);
382619a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
3827bfcba38dSTomi Valkeinen 	mutex_destroy(&sensor->lock);
382819a81c14SSteve Longerbeam 
382919a81c14SSteve Longerbeam 	return 0;
383019a81c14SSteve Longerbeam }
383119a81c14SSteve Longerbeam 
383219a81c14SSteve Longerbeam static const struct i2c_device_id ov5640_id[] = {
383319a81c14SSteve Longerbeam 	{"ov5640", 0},
383419a81c14SSteve Longerbeam 	{},
383519a81c14SSteve Longerbeam };
383619a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(i2c, ov5640_id);
383719a81c14SSteve Longerbeam 
383819a81c14SSteve Longerbeam static const struct of_device_id ov5640_dt_ids[] = {
383919a81c14SSteve Longerbeam 	{ .compatible = "ovti,ov5640" },
384019a81c14SSteve Longerbeam 	{ /* sentinel */ }
384119a81c14SSteve Longerbeam };
384219a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(of, ov5640_dt_ids);
384319a81c14SSteve Longerbeam 
384419a81c14SSteve Longerbeam static struct i2c_driver ov5640_i2c_driver = {
384519a81c14SSteve Longerbeam 	.driver = {
384619a81c14SSteve Longerbeam 		.name  = "ov5640",
384719a81c14SSteve Longerbeam 		.of_match_table	= ov5640_dt_ids,
384819a81c14SSteve Longerbeam 	},
384919a81c14SSteve Longerbeam 	.id_table = ov5640_id,
3850e6714993SKieran Bingham 	.probe_new = ov5640_probe,
385119a81c14SSteve Longerbeam 	.remove   = ov5640_remove,
385219a81c14SSteve Longerbeam };
385319a81c14SSteve Longerbeam 
385419a81c14SSteve Longerbeam module_i2c_driver(ov5640_i2c_driver);
385519a81c14SSteve Longerbeam 
385619a81c14SSteve Longerbeam MODULE_DESCRIPTION("OV5640 MIPI Camera Subdev Driver");
385719a81c14SSteve Longerbeam MODULE_LICENSE("GPL");
3858