xref: /openbmc/linux/drivers/media/i2c/ov5640.c (revision dd81b8ff)
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 	}, {
2250a43fcd7SJacopo Mondi 		.code = MEDIA_BUS_FMT_RGB565_1X16,
2260a43fcd7SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2270a43fcd7SJacopo Mondi 		.bpp = 16,
2280a43fcd7SJacopo Mondi 	}, {
2296ac98b41SJacopo Mondi 		.code = MEDIA_BUS_FMT_BGR888_1X24,
2306ac98b41SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2316ac98b41SJacopo Mondi 		.bpp = 24,
2326ac98b41SJacopo Mondi 	}, {
2332d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_SBGGR8_1X8,
2342d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2352d7671f6SJacopo Mondi 		.bpp = 8,
2362d7671f6SJacopo Mondi 	}, {
2372d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_SGBRG8_1X8,
2382d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2392d7671f6SJacopo Mondi 		.bpp = 8
2402d7671f6SJacopo Mondi 	}, {
2412d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_SGRBG8_1X8,
2422d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2432d7671f6SJacopo Mondi 		.bpp = 8,
2442d7671f6SJacopo Mondi 	}, {
2452d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_SRGGB8_1X8,
2462d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2472d7671f6SJacopo Mondi 		.bpp = 8,
2482d7671f6SJacopo Mondi 	},
249e3ee691dSHugues Fruchet };
250e3ee691dSHugues Fruchet 
2513c28588fSJacopo Mondi static u32 ov5640_code_to_bpp(u32 code)
2523c28588fSJacopo Mondi {
2533c28588fSJacopo Mondi 	unsigned int i;
2543c28588fSJacopo Mondi 
2553c28588fSJacopo Mondi 	for (i = 0; i < ARRAY_SIZE(ov5640_formats); ++i) {
2563c28588fSJacopo Mondi 		if (ov5640_formats[i].code == code)
2573c28588fSJacopo Mondi 			return ov5640_formats[i].bpp;
2583c28588fSJacopo Mondi 	}
2593c28588fSJacopo Mondi 
2603c28588fSJacopo Mondi 	return 0;
2613c28588fSJacopo Mondi }
2623c28588fSJacopo Mondi 
26319a81c14SSteve Longerbeam /*
26419a81c14SSteve Longerbeam  * FIXME: remove this when a subdev API becomes available
26519a81c14SSteve Longerbeam  * to set the MIPI CSI-2 virtual channel.
26619a81c14SSteve Longerbeam  */
26719a81c14SSteve Longerbeam static unsigned int virtual_channel;
2688670d70aSHugues Fruchet module_param(virtual_channel, uint, 0444);
26919a81c14SSteve Longerbeam MODULE_PARM_DESC(virtual_channel,
27019a81c14SSteve Longerbeam 		 "MIPI CSI-2 virtual channel (0..3), default 0");
27119a81c14SSteve Longerbeam 
27219a81c14SSteve Longerbeam static const int ov5640_framerates[] = {
27319a81c14SSteve Longerbeam 	[OV5640_15_FPS] = 15,
27419a81c14SSteve Longerbeam 	[OV5640_30_FPS] = 30,
275e823fb16SMaxime Ripard 	[OV5640_60_FPS] = 60,
27619a81c14SSteve Longerbeam };
27719a81c14SSteve Longerbeam 
27819a81c14SSteve Longerbeam /* regulator supplies */
27919a81c14SSteve Longerbeam static const char * const ov5640_supply_name[] = {
28041d8d7f5SHugues Fruchet 	"DOVDD", /* Digital I/O (1.8V) supply */
28119a81c14SSteve Longerbeam 	"AVDD",  /* Analog (2.8V) supply */
28224c8ac89SFabio Estevam 	"DVDD",  /* Digital Core (1.5V) supply */
28319a81c14SSteve Longerbeam };
28419a81c14SSteve Longerbeam 
28519a81c14SSteve Longerbeam #define OV5640_NUM_SUPPLIES ARRAY_SIZE(ov5640_supply_name)
28619a81c14SSteve Longerbeam 
28719a81c14SSteve Longerbeam /*
28819a81c14SSteve Longerbeam  * Image size under 1280 * 960 are SUBSAMPLING
28919a81c14SSteve Longerbeam  * Image size upper 1280 * 960 are SCALING
29019a81c14SSteve Longerbeam  */
29119a81c14SSteve Longerbeam enum ov5640_downsize_mode {
29219a81c14SSteve Longerbeam 	SUBSAMPLING,
29319a81c14SSteve Longerbeam 	SCALING,
29419a81c14SSteve Longerbeam };
29519a81c14SSteve Longerbeam 
29619a81c14SSteve Longerbeam struct reg_value {
29719a81c14SSteve Longerbeam 	u16 reg_addr;
29819a81c14SSteve Longerbeam 	u8 val;
29919a81c14SSteve Longerbeam 	u8 mask;
30019a81c14SSteve Longerbeam 	u32 delay_ms;
30119a81c14SSteve Longerbeam };
30219a81c14SSteve Longerbeam 
3035113d5b3SJacopo Mondi struct ov5640_timings {
3043145efcdSJacopo Mondi 	/* Analog crop rectangle. */
3053145efcdSJacopo Mondi 	struct v4l2_rect analog_crop;
3063145efcdSJacopo Mondi 	/* Visibile crop: from analog crop top-left corner. */
3073145efcdSJacopo Mondi 	struct v4l2_rect crop;
3085113d5b3SJacopo Mondi 	/* Total pixels per line: width + fixed hblank. */
309476dec01SMaxime Ripard 	u32 htot;
3105113d5b3SJacopo Mondi 	/* Default vertical blanking: frame height = height + vblank. */
3113145efcdSJacopo Mondi 	u32 vblank_def;
3125113d5b3SJacopo Mondi };
3135113d5b3SJacopo Mondi 
3145113d5b3SJacopo Mondi struct ov5640_mode_info {
3155113d5b3SJacopo Mondi 	enum ov5640_mode_id id;
3165113d5b3SJacopo Mondi 	enum ov5640_downsize_mode dn_mode;
3175113d5b3SJacopo Mondi 	enum ov5640_pixel_rate_id pixel_rate;
3185113d5b3SJacopo Mondi 
3195113d5b3SJacopo Mondi 	unsigned int width;
3205113d5b3SJacopo Mondi 	unsigned int height;
3215113d5b3SJacopo Mondi 
3225113d5b3SJacopo Mondi 	struct ov5640_timings dvp_timings;
3235113d5b3SJacopo Mondi 	struct ov5640_timings csi2_timings;
3245113d5b3SJacopo Mondi 
32519a81c14SSteve Longerbeam 	const struct reg_value *reg_data;
32619a81c14SSteve Longerbeam 	u32 reg_data_size;
3275113d5b3SJacopo Mondi 
3285113d5b3SJacopo Mondi 	/* Used by s_frame_interval only. */
3295554c80eSAdam Ford 	u32 max_fps;
33019f2e3e6SHugues Fruchet 	u32 def_fps;
33119a81c14SSteve Longerbeam };
33219a81c14SSteve Longerbeam 
33319a81c14SSteve Longerbeam struct ov5640_ctrls {
33419a81c14SSteve Longerbeam 	struct v4l2_ctrl_handler handler;
335cc196e48SBenoit Parrot 	struct v4l2_ctrl *pixel_rate;
3367a3b8d4bSJacopo Mondi 	struct v4l2_ctrl *link_freq;
33732979f67SJacopo Mondi 	struct v4l2_ctrl *hblank;
338bce93b82SJacopo Mondi 	struct v4l2_ctrl *vblank;
33919a81c14SSteve Longerbeam 	struct {
34019a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_exp;
34119a81c14SSteve Longerbeam 		struct v4l2_ctrl *exposure;
34219a81c14SSteve Longerbeam 	};
34319a81c14SSteve Longerbeam 	struct {
34419a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_wb;
34519a81c14SSteve Longerbeam 		struct v4l2_ctrl *blue_balance;
34619a81c14SSteve Longerbeam 		struct v4l2_ctrl *red_balance;
34719a81c14SSteve Longerbeam 	};
34819a81c14SSteve Longerbeam 	struct {
34919a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_gain;
35019a81c14SSteve Longerbeam 		struct v4l2_ctrl *gain;
35119a81c14SSteve Longerbeam 	};
35219a81c14SSteve Longerbeam 	struct v4l2_ctrl *brightness;
3531068fecaSMylène Josserand 	struct v4l2_ctrl *light_freq;
35419a81c14SSteve Longerbeam 	struct v4l2_ctrl *saturation;
35519a81c14SSteve Longerbeam 	struct v4l2_ctrl *contrast;
35619a81c14SSteve Longerbeam 	struct v4l2_ctrl *hue;
35719a81c14SSteve Longerbeam 	struct v4l2_ctrl *test_pattern;
358ce85705aSHugues Fruchet 	struct v4l2_ctrl *hflip;
359ce85705aSHugues Fruchet 	struct v4l2_ctrl *vflip;
36019a81c14SSteve Longerbeam };
36119a81c14SSteve Longerbeam 
36219a81c14SSteve Longerbeam struct ov5640_dev {
36319a81c14SSteve Longerbeam 	struct i2c_client *i2c_client;
36419a81c14SSteve Longerbeam 	struct v4l2_subdev sd;
36519a81c14SSteve Longerbeam 	struct media_pad pad;
36619a81c14SSteve Longerbeam 	struct v4l2_fwnode_endpoint ep; /* the parsed DT endpoint info */
36719a81c14SSteve Longerbeam 	struct clk *xclk; /* system clock to OV5640 */
36819a81c14SSteve Longerbeam 	u32 xclk_freq;
36919a81c14SSteve Longerbeam 
37019a81c14SSteve Longerbeam 	struct regulator_bulk_data supplies[OV5640_NUM_SUPPLIES];
37119a81c14SSteve Longerbeam 	struct gpio_desc *reset_gpio;
37219a81c14SSteve Longerbeam 	struct gpio_desc *pwdn_gpio;
373c3f3ba3eSHugues Fruchet 	bool   upside_down;
37419a81c14SSteve Longerbeam 
37519a81c14SSteve Longerbeam 	/* lock to protect all members below */
37619a81c14SSteve Longerbeam 	struct mutex lock;
37719a81c14SSteve Longerbeam 
37819a81c14SSteve Longerbeam 	int power_count;
37919a81c14SSteve Longerbeam 
38019a81c14SSteve Longerbeam 	struct v4l2_mbus_framefmt fmt;
381fb98e29fSHugues Fruchet 	bool pending_fmt_change;
38219a81c14SSteve Longerbeam 
38319a81c14SSteve Longerbeam 	const struct ov5640_mode_info *current_mode;
384985cdcb0SHugues Fruchet 	const struct ov5640_mode_info *last_mode;
38519a81c14SSteve Longerbeam 	enum ov5640_frame_rate current_fr;
38619a81c14SSteve Longerbeam 	struct v4l2_fract frame_interval;
3873c28588fSJacopo Mondi 	s64 current_link_freq;
38819a81c14SSteve Longerbeam 
38919a81c14SSteve Longerbeam 	struct ov5640_ctrls ctrls;
39019a81c14SSteve Longerbeam 
39119a81c14SSteve Longerbeam 	u32 prev_sysclk, prev_hts;
39219a81c14SSteve Longerbeam 	u32 ae_low, ae_high, ae_target;
39319a81c14SSteve Longerbeam 
39419a81c14SSteve Longerbeam 	bool pending_mode_change;
39519a81c14SSteve Longerbeam 	bool streaming;
39619a81c14SSteve Longerbeam };
39719a81c14SSteve Longerbeam 
39819a81c14SSteve Longerbeam static inline struct ov5640_dev *to_ov5640_dev(struct v4l2_subdev *sd)
39919a81c14SSteve Longerbeam {
40019a81c14SSteve Longerbeam 	return container_of(sd, struct ov5640_dev, sd);
40119a81c14SSteve Longerbeam }
40219a81c14SSteve Longerbeam 
40319a81c14SSteve Longerbeam static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
40419a81c14SSteve Longerbeam {
40519a81c14SSteve Longerbeam 	return &container_of(ctrl->handler, struct ov5640_dev,
40619a81c14SSteve Longerbeam 			     ctrls.handler)->sd;
40719a81c14SSteve Longerbeam }
40819a81c14SSteve Longerbeam 
4098e823f5cSJacopo Mondi static inline bool ov5640_is_csi2(const struct ov5640_dev *sensor)
4108e823f5cSJacopo Mondi {
4118e823f5cSJacopo Mondi 	return sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY;
4128e823f5cSJacopo Mondi }
4138e823f5cSJacopo Mondi 
41419a81c14SSteve Longerbeam /*
41519a81c14SSteve Longerbeam  * FIXME: all of these register tables are likely filled with
41619a81c14SSteve Longerbeam  * entries that set the register to their power-on default values,
41719a81c14SSteve Longerbeam  * and which are otherwise not touched by this driver. Those entries
41819a81c14SSteve Longerbeam  * should be identified and removed to speed register load time
41919a81c14SSteve Longerbeam  * over i2c.
42019a81c14SSteve Longerbeam  */
421fb98e29fSHugues Fruchet /* YUV422 UYVY VGA@30fps */
42290b0f355SJacopo Mondi 
42390b0f355SJacopo Mondi static const struct v4l2_mbus_framefmt ov5640_default_fmt = {
42490b0f355SJacopo Mondi 	.code = MEDIA_BUS_FMT_UYVY8_2X8,
42590b0f355SJacopo Mondi 	.width = 640,
42690b0f355SJacopo Mondi 	.height = 480,
42790b0f355SJacopo Mondi 	.colorspace = V4L2_COLORSPACE_SRGB,
42890b0f355SJacopo Mondi 	.ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SRGB),
42990b0f355SJacopo Mondi 	.quantization = V4L2_QUANTIZATION_FULL_RANGE,
43090b0f355SJacopo Mondi 	.xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SRGB),
43190b0f355SJacopo Mondi 	.field = V4L2_FIELD_NONE,
43290b0f355SJacopo Mondi };
43390b0f355SJacopo Mondi 
434e4359019SJacopo Mondi static const struct reg_value ov5640_init_setting[] = {
43519a81c14SSteve Longerbeam 	{0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0},
436576f5d4bSLad Prabhakar 	{0x3103, 0x03, 0, 0}, {0x3630, 0x36, 0, 0},
43719a81c14SSteve Longerbeam 	{0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0},
43819a81c14SSteve Longerbeam 	{0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0},
43919a81c14SSteve Longerbeam 	{0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0},
44019a81c14SSteve Longerbeam 	{0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, {0x3906, 0x10, 0, 0},
44119a81c14SSteve Longerbeam 	{0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, {0x3600, 0x08, 0, 0},
44219a81c14SSteve Longerbeam 	{0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, {0x3620, 0x52, 0, 0},
44319a81c14SSteve Longerbeam 	{0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, {0x3a13, 0x43, 0, 0},
44419a81c14SSteve Longerbeam 	{0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3635, 0x13, 0, 0},
44519a81c14SSteve Longerbeam 	{0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, {0x3622, 0x01, 0, 0},
44619a81c14SSteve Longerbeam 	{0x3c01, 0xa4, 0, 0}, {0x3c04, 0x28, 0, 0}, {0x3c05, 0x98, 0, 0},
44719a81c14SSteve Longerbeam 	{0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0},
44819a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
44919a81c14SSteve Longerbeam 	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
4503145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
45119a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
45219a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
45319a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
45419a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
45519a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
45619a81c14SSteve Longerbeam 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0},
45719a81c14SSteve Longerbeam 	{0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0},
458aa4bb8b8SJacopo Mondi 	{0x302e, 0x08, 0, 0}, {0x4300, 0x3f, 0, 0},
4592b5c18f9SChen-Yu Tsai 	{0x501f, 0x00, 0, 0}, {0x4407, 0x04, 0, 0},
46019a81c14SSteve Longerbeam 	{0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
461aa4bb8b8SJacopo Mondi 	{0x4837, 0x0a, 0, 0}, {0x3824, 0x02, 0, 0},
46219a81c14SSteve Longerbeam 	{0x5000, 0xa7, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0},
46319a81c14SSteve Longerbeam 	{0x5181, 0xf2, 0, 0}, {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0},
46419a81c14SSteve Longerbeam 	{0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0},
46519a81c14SSteve Longerbeam 	{0x5187, 0x09, 0, 0}, {0x5188, 0x09, 0, 0}, {0x5189, 0x88, 0, 0},
46619a81c14SSteve Longerbeam 	{0x518a, 0x54, 0, 0}, {0x518b, 0xee, 0, 0}, {0x518c, 0xb2, 0, 0},
46719a81c14SSteve Longerbeam 	{0x518d, 0x50, 0, 0}, {0x518e, 0x34, 0, 0}, {0x518f, 0x6b, 0, 0},
46819a81c14SSteve Longerbeam 	{0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0},
46919a81c14SSteve Longerbeam 	{0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0},
47019a81c14SSteve Longerbeam 	{0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0},
47119a81c14SSteve Longerbeam 	{0x5199, 0x6c, 0, 0}, {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0},
47219a81c14SSteve Longerbeam 	{0x519c, 0x09, 0, 0}, {0x519d, 0x2b, 0, 0}, {0x519e, 0x38, 0, 0},
47319a81c14SSteve Longerbeam 	{0x5381, 0x1e, 0, 0}, {0x5382, 0x5b, 0, 0}, {0x5383, 0x08, 0, 0},
47419a81c14SSteve Longerbeam 	{0x5384, 0x0a, 0, 0}, {0x5385, 0x7e, 0, 0}, {0x5386, 0x88, 0, 0},
47519a81c14SSteve Longerbeam 	{0x5387, 0x7c, 0, 0}, {0x5388, 0x6c, 0, 0}, {0x5389, 0x10, 0, 0},
47619a81c14SSteve Longerbeam 	{0x538a, 0x01, 0, 0}, {0x538b, 0x98, 0, 0}, {0x5300, 0x08, 0, 0},
47719a81c14SSteve Longerbeam 	{0x5301, 0x30, 0, 0}, {0x5302, 0x10, 0, 0}, {0x5303, 0x00, 0, 0},
47819a81c14SSteve Longerbeam 	{0x5304, 0x08, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x08, 0, 0},
47919a81c14SSteve Longerbeam 	{0x5307, 0x16, 0, 0}, {0x5309, 0x08, 0, 0}, {0x530a, 0x30, 0, 0},
48019a81c14SSteve Longerbeam 	{0x530b, 0x04, 0, 0}, {0x530c, 0x06, 0, 0}, {0x5480, 0x01, 0, 0},
48119a81c14SSteve Longerbeam 	{0x5481, 0x08, 0, 0}, {0x5482, 0x14, 0, 0}, {0x5483, 0x28, 0, 0},
48219a81c14SSteve Longerbeam 	{0x5484, 0x51, 0, 0}, {0x5485, 0x65, 0, 0}, {0x5486, 0x71, 0, 0},
48319a81c14SSteve Longerbeam 	{0x5487, 0x7d, 0, 0}, {0x5488, 0x87, 0, 0}, {0x5489, 0x91, 0, 0},
48419a81c14SSteve Longerbeam 	{0x548a, 0x9a, 0, 0}, {0x548b, 0xaa, 0, 0}, {0x548c, 0xb8, 0, 0},
48519a81c14SSteve Longerbeam 	{0x548d, 0xcd, 0, 0}, {0x548e, 0xdd, 0, 0}, {0x548f, 0xea, 0, 0},
48619a81c14SSteve Longerbeam 	{0x5490, 0x1d, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5583, 0x40, 0, 0},
48719a81c14SSteve Longerbeam 	{0x5584, 0x10, 0, 0}, {0x5589, 0x10, 0, 0}, {0x558a, 0x00, 0, 0},
48819a81c14SSteve Longerbeam 	{0x558b, 0xf8, 0, 0}, {0x5800, 0x23, 0, 0}, {0x5801, 0x14, 0, 0},
48919a81c14SSteve Longerbeam 	{0x5802, 0x0f, 0, 0}, {0x5803, 0x0f, 0, 0}, {0x5804, 0x12, 0, 0},
49019a81c14SSteve Longerbeam 	{0x5805, 0x26, 0, 0}, {0x5806, 0x0c, 0, 0}, {0x5807, 0x08, 0, 0},
49119a81c14SSteve Longerbeam 	{0x5808, 0x05, 0, 0}, {0x5809, 0x05, 0, 0}, {0x580a, 0x08, 0, 0},
49219a81c14SSteve Longerbeam 	{0x580b, 0x0d, 0, 0}, {0x580c, 0x08, 0, 0}, {0x580d, 0x03, 0, 0},
49319a81c14SSteve Longerbeam 	{0x580e, 0x00, 0, 0}, {0x580f, 0x00, 0, 0}, {0x5810, 0x03, 0, 0},
49419a81c14SSteve Longerbeam 	{0x5811, 0x09, 0, 0}, {0x5812, 0x07, 0, 0}, {0x5813, 0x03, 0, 0},
49519a81c14SSteve Longerbeam 	{0x5814, 0x00, 0, 0}, {0x5815, 0x01, 0, 0}, {0x5816, 0x03, 0, 0},
49619a81c14SSteve Longerbeam 	{0x5817, 0x08, 0, 0}, {0x5818, 0x0d, 0, 0}, {0x5819, 0x08, 0, 0},
49719a81c14SSteve Longerbeam 	{0x581a, 0x05, 0, 0}, {0x581b, 0x06, 0, 0}, {0x581c, 0x08, 0, 0},
49819a81c14SSteve Longerbeam 	{0x581d, 0x0e, 0, 0}, {0x581e, 0x29, 0, 0}, {0x581f, 0x17, 0, 0},
49919a81c14SSteve Longerbeam 	{0x5820, 0x11, 0, 0}, {0x5821, 0x11, 0, 0}, {0x5822, 0x15, 0, 0},
50019a81c14SSteve Longerbeam 	{0x5823, 0x28, 0, 0}, {0x5824, 0x46, 0, 0}, {0x5825, 0x26, 0, 0},
50119a81c14SSteve Longerbeam 	{0x5826, 0x08, 0, 0}, {0x5827, 0x26, 0, 0}, {0x5828, 0x64, 0, 0},
50219a81c14SSteve Longerbeam 	{0x5829, 0x26, 0, 0}, {0x582a, 0x24, 0, 0}, {0x582b, 0x22, 0, 0},
50319a81c14SSteve Longerbeam 	{0x582c, 0x24, 0, 0}, {0x582d, 0x24, 0, 0}, {0x582e, 0x06, 0, 0},
50419a81c14SSteve Longerbeam 	{0x582f, 0x22, 0, 0}, {0x5830, 0x40, 0, 0}, {0x5831, 0x42, 0, 0},
50519a81c14SSteve Longerbeam 	{0x5832, 0x24, 0, 0}, {0x5833, 0x26, 0, 0}, {0x5834, 0x24, 0, 0},
50619a81c14SSteve Longerbeam 	{0x5835, 0x22, 0, 0}, {0x5836, 0x22, 0, 0}, {0x5837, 0x26, 0, 0},
50719a81c14SSteve Longerbeam 	{0x5838, 0x44, 0, 0}, {0x5839, 0x24, 0, 0}, {0x583a, 0x26, 0, 0},
50819a81c14SSteve Longerbeam 	{0x583b, 0x28, 0, 0}, {0x583c, 0x42, 0, 0}, {0x583d, 0xce, 0, 0},
50919a81c14SSteve Longerbeam 	{0x5025, 0x00, 0, 0}, {0x3a0f, 0x30, 0, 0}, {0x3a10, 0x28, 0, 0},
51019a81c14SSteve Longerbeam 	{0x3a1b, 0x30, 0, 0}, {0x3a1e, 0x26, 0, 0}, {0x3a11, 0x60, 0, 0},
51119a81c14SSteve Longerbeam 	{0x3a1f, 0x14, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3c00, 0x04, 0, 300},
51219a81c14SSteve Longerbeam };
51319a81c14SSteve Longerbeam 
514db15c195SJacopo Mondi static const struct reg_value ov5640_setting_low_res[] = {
515c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
51619a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
517ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
5183145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
51919a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
52019a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
52119a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
52219a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
52319a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5242b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
525e15197bdSJacopo Mondi 	{0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0},
52619a81c14SSteve Longerbeam };
52719a81c14SSteve Longerbeam 
528086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_720P_1280_720[] = {
529c14d107eSMaxime Ripard 	{0x3c07, 0x07, 0, 0},
53019a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
531ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
5323145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
53319a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
53419a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0},
53519a81c14SSteve Longerbeam 	{0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0},
53619a81c14SSteve Longerbeam 	{0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0},
53719a81c14SSteve Longerbeam 	{0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0},
5382b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
53919a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
54019a81c14SSteve Longerbeam 	{0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0},
54119a81c14SSteve Longerbeam };
54219a81c14SSteve Longerbeam 
543086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_1080P_1920_1080[] = {
544c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
54519a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
546ce85705aSHugues Fruchet 	{0x3814, 0x11, 0, 0},
5473145efcdSJacopo Mondi 	{0x3815, 0x11, 0, 0},
54819a81c14SSteve Longerbeam 	{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
54919a81c14SSteve Longerbeam 	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
55019a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
55119a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
55219a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5532b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0},
55419a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
555c14d107eSMaxime Ripard 	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0},
556c14d107eSMaxime Ripard 	{0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0},
55719a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
558476dec01SMaxime Ripard 	{0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0},
55919a81c14SSteve Longerbeam 	{0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0},
56019a81c14SSteve Longerbeam 	{0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0},
56119a81c14SSteve Longerbeam 	{0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0},
5622b5c18f9SChen-Yu Tsai 	{0x3a15, 0x60, 0, 0}, {0x4407, 0x04, 0, 0},
56319a81c14SSteve Longerbeam 	{0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0},
56492b9096cSBenoit Parrot 	{0x4005, 0x1a, 0, 0},
56519a81c14SSteve Longerbeam };
56619a81c14SSteve Longerbeam 
567086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_QSXGA_2592_1944[] = {
568c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
56919a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
570ce85705aSHugues Fruchet 	{0x3814, 0x11, 0, 0},
5713145efcdSJacopo Mondi 	{0x3815, 0x11, 0, 0},
57219a81c14SSteve Longerbeam 	{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
57319a81c14SSteve Longerbeam 	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
57419a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
57519a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
57619a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5772b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0},
57819a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
57919a81c14SSteve Longerbeam 	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70},
58019a81c14SSteve Longerbeam };
58119a81c14SSteve Longerbeam 
5825113d5b3SJacopo Mondi static const struct ov5640_mode_info ov5640_mode_data[OV5640_NUM_MODES] = {
5838409d017SJacopo Mondi 	{
5848409d017SJacopo Mondi 		/* 160x120 */
5853145efcdSJacopo Mondi 		.id		= OV5640_MODE_QQVGA_160_120,
5863145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
5873145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
5885113d5b3SJacopo Mondi 		.width		= 160,
5895113d5b3SJacopo Mondi 		.height		= 120,
5905113d5b3SJacopo Mondi 		.dvp_timings = {
5913145efcdSJacopo Mondi 			.analog_crop = {
5923145efcdSJacopo Mondi 				.left	= 0,
5933145efcdSJacopo Mondi 				.top	= 4,
5943145efcdSJacopo Mondi 				.width	= 2624,
5953145efcdSJacopo Mondi 				.height	= 1944,
5963145efcdSJacopo Mondi 			},
5973145efcdSJacopo Mondi 			.crop = {
5983145efcdSJacopo Mondi 				.left	= 16,
5993145efcdSJacopo Mondi 				.top	= 6,
6003145efcdSJacopo Mondi 				.width	= 160,
6013145efcdSJacopo Mondi 				.height	= 120,
6023145efcdSJacopo Mondi 			},
6033145efcdSJacopo Mondi 			.htot		= 1896,
6043145efcdSJacopo Mondi 			.vblank_def	= 864,
6055113d5b3SJacopo Mondi 		},
6065113d5b3SJacopo Mondi 		.csi2_timings = {
6075113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
6085113d5b3SJacopo Mondi 			.analog_crop = {
6095113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
6105113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
6115113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
6125113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
6135113d5b3SJacopo Mondi 			},
6145113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
6155113d5b3SJacopo Mondi 			.crop = {
6165113d5b3SJacopo Mondi 				.left	= 2,
6175113d5b3SJacopo Mondi 				.top	= 4,
6185113d5b3SJacopo Mondi 				.width	= 160,
6195113d5b3SJacopo Mondi 				.height	= 120,
6205113d5b3SJacopo Mondi 			},
621961bed9fSJacopo Mondi 			.htot		= 1600,
622961bed9fSJacopo Mondi 			.vblank_def	= 878,
6235113d5b3SJacopo Mondi 		},
624db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
625db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
62619f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
62719f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
6288409d017SJacopo Mondi 	}, {
6298409d017SJacopo Mondi 		/* 176x144 */
6303145efcdSJacopo Mondi 		.id		= OV5640_MODE_QCIF_176_144,
6313145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
6323145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
6335113d5b3SJacopo Mondi 		.width		= 176,
6345113d5b3SJacopo Mondi 		.height		= 144,
6355113d5b3SJacopo Mondi 		.dvp_timings = {
6363145efcdSJacopo Mondi 			.analog_crop = {
6373145efcdSJacopo Mondi 				.left	= 0,
6383145efcdSJacopo Mondi 				.top	= 4,
6393145efcdSJacopo Mondi 				.width	= 2624,
6403145efcdSJacopo Mondi 				.height	= 1944,
6413145efcdSJacopo Mondi 			},
6423145efcdSJacopo Mondi 			.crop = {
6433145efcdSJacopo Mondi 				.left	= 16,
6443145efcdSJacopo Mondi 				.top	= 6,
6453145efcdSJacopo Mondi 				.width	= 176,
6463145efcdSJacopo Mondi 				.height	= 144,
6473145efcdSJacopo Mondi 			},
6483145efcdSJacopo Mondi 			.htot		= 1896,
6493145efcdSJacopo Mondi 			.vblank_def	= 840,
6505113d5b3SJacopo Mondi 		},
6515113d5b3SJacopo Mondi 		.csi2_timings = {
6525113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
6535113d5b3SJacopo Mondi 			.analog_crop = {
6545113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
6555113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
6565113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
6575113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
6585113d5b3SJacopo Mondi 			},
6595113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
6605113d5b3SJacopo Mondi 			.crop = {
6615113d5b3SJacopo Mondi 				.left	= 2,
6625113d5b3SJacopo Mondi 				.top	= 4,
6635113d5b3SJacopo Mondi 				.width	= 176,
6645113d5b3SJacopo Mondi 				.height	= 144,
6655113d5b3SJacopo Mondi 			},
666961bed9fSJacopo Mondi 			.htot		= 1600,
667961bed9fSJacopo Mondi 			.vblank_def	= 854,
6685113d5b3SJacopo Mondi 		},
669db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
670db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
67119f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
67219f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
6738409d017SJacopo Mondi 	}, {
6748409d017SJacopo Mondi 		/* 320x240 */
6753145efcdSJacopo Mondi 		.id		= OV5640_MODE_QVGA_320_240,
6763145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
6775113d5b3SJacopo Mondi 		.width		= 320,
6785113d5b3SJacopo Mondi 		.height		= 240,
6793145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
6805113d5b3SJacopo Mondi 		.dvp_timings = {
6813145efcdSJacopo Mondi 			.analog_crop = {
6823145efcdSJacopo Mondi 				.left	= 0,
6833145efcdSJacopo Mondi 				.top	= 4,
6843145efcdSJacopo Mondi 				.width	= 2624,
6853145efcdSJacopo Mondi 				.height	= 1944,
6863145efcdSJacopo Mondi 			},
6873145efcdSJacopo Mondi 			.crop = {
6883145efcdSJacopo Mondi 				.left	= 16,
6893145efcdSJacopo Mondi 				.top	= 6,
6903145efcdSJacopo Mondi 				.width	= 320,
6913145efcdSJacopo Mondi 				.height	= 240,
6923145efcdSJacopo Mondi 			},
6933145efcdSJacopo Mondi 			.htot		= 1896,
6943145efcdSJacopo Mondi 			.vblank_def	= 744,
6955113d5b3SJacopo Mondi 		},
6965113d5b3SJacopo Mondi 		.csi2_timings = {
6975113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
6985113d5b3SJacopo Mondi 			.analog_crop = {
6995113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
7005113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
7015113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
7025113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
7035113d5b3SJacopo Mondi 			},
7045113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
7055113d5b3SJacopo Mondi 			.crop = {
7065113d5b3SJacopo Mondi 				.left	= 2,
7075113d5b3SJacopo Mondi 				.top	= 4,
7085113d5b3SJacopo Mondi 				.width	= 320,
7095113d5b3SJacopo Mondi 				.height	= 240,
7105113d5b3SJacopo Mondi 			},
711961bed9fSJacopo Mondi 			.htot		= 1600,
712961bed9fSJacopo Mondi 			.vblank_def	= 760,
7135113d5b3SJacopo Mondi 		},
714db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
715db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
71619f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
71719f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
7188409d017SJacopo Mondi 	}, {
7198409d017SJacopo Mondi 		/* 640x480 */
7203145efcdSJacopo Mondi 		.id		= OV5640_MODE_VGA_640_480,
7213145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
7223145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
7235113d5b3SJacopo Mondi 		.width		= 640,
7245113d5b3SJacopo Mondi 		.height		= 480,
7255113d5b3SJacopo Mondi 		.dvp_timings = {
7263145efcdSJacopo Mondi 			.analog_crop = {
7273145efcdSJacopo Mondi 				.left	= 0,
7283145efcdSJacopo Mondi 				.top	= 4,
7293145efcdSJacopo Mondi 				.width	= 2624,
7303145efcdSJacopo Mondi 				.height	= 1944,
7313145efcdSJacopo Mondi 			},
7323145efcdSJacopo Mondi 			.crop = {
7333145efcdSJacopo Mondi 				.left	= 16,
7343145efcdSJacopo Mondi 				.top	= 6,
7353145efcdSJacopo Mondi 				.width	= 640,
7363145efcdSJacopo Mondi 				.height	= 480,
7373145efcdSJacopo Mondi 			},
7383145efcdSJacopo Mondi 			.htot		= 1896,
7393145efcdSJacopo Mondi 			.vblank_def	= 600,
7405113d5b3SJacopo Mondi 		},
7415113d5b3SJacopo Mondi 		.csi2_timings = {
7425113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
7435113d5b3SJacopo Mondi 			.analog_crop = {
7445113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
7455113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
7465113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
7475113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
7485113d5b3SJacopo Mondi 			},
7495113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
7505113d5b3SJacopo Mondi 			.crop = {
7515113d5b3SJacopo Mondi 				.left	= 2,
7525113d5b3SJacopo Mondi 				.top	= 4,
7535113d5b3SJacopo Mondi 				.width	= 640,
7545113d5b3SJacopo Mondi 				.height	= 480,
7555113d5b3SJacopo Mondi 			},
756961bed9fSJacopo Mondi 			.htot		= 1600,
757961bed9fSJacopo Mondi 			.vblank_def	= 520,
7585113d5b3SJacopo Mondi 		},
759db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
760db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
76119f2e3e6SHugues Fruchet 		.max_fps	= OV5640_60_FPS,
76219f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
7638409d017SJacopo Mondi 	}, {
7648409d017SJacopo Mondi 		/* 720x480 */
7653145efcdSJacopo Mondi 		.id		= OV5640_MODE_NTSC_720_480,
7663145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
7675113d5b3SJacopo Mondi 		.width		= 720,
7685113d5b3SJacopo Mondi 		.height		= 480,
7693145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
7705113d5b3SJacopo Mondi 		.dvp_timings = {
7713145efcdSJacopo Mondi 			.analog_crop = {
7723145efcdSJacopo Mondi 				.left	= 0,
7733145efcdSJacopo Mondi 				.top	= 4,
7743145efcdSJacopo Mondi 				.width	= 2624,
7753145efcdSJacopo Mondi 				.height	= 1944,
7763145efcdSJacopo Mondi 			},
7773145efcdSJacopo Mondi 			.crop = {
778e74ef55bSJacopo Mondi 				.left	= 56,
7793145efcdSJacopo Mondi 				.top	= 60,
7803145efcdSJacopo Mondi 				.width	= 720,
7813145efcdSJacopo Mondi 				.height	= 480,
7823145efcdSJacopo Mondi 			},
7833145efcdSJacopo Mondi 			.htot		= 1896,
7843145efcdSJacopo Mondi 			.vblank_def	= 504,
7855113d5b3SJacopo Mondi 		},
7865113d5b3SJacopo Mondi 		.csi2_timings = {
7875113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
7885113d5b3SJacopo Mondi 			.analog_crop = {
7895113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
7905113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
7915113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
7925113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
7935113d5b3SJacopo Mondi 			},
7945113d5b3SJacopo Mondi 			.crop = {
7955113d5b3SJacopo Mondi 				.left	= 56,
7965113d5b3SJacopo Mondi 				.top	= 60,
7975113d5b3SJacopo Mondi 				.width	= 720,
7985113d5b3SJacopo Mondi 				.height	= 480,
7995113d5b3SJacopo Mondi 			},
8005113d5b3SJacopo Mondi 			.htot		= 1896,
801961bed9fSJacopo Mondi 			.vblank_def	= 1206,
8025113d5b3SJacopo Mondi 		},
803db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
804db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
80519f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
80619f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
8078409d017SJacopo Mondi 	}, {
8088409d017SJacopo Mondi 		/* 720x576 */
8093145efcdSJacopo Mondi 		.id		= OV5640_MODE_PAL_720_576,
8103145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
8115113d5b3SJacopo Mondi 		.width		= 720,
8125113d5b3SJacopo Mondi 		.height		= 576,
8133145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
8145113d5b3SJacopo Mondi 		.dvp_timings = {
8153145efcdSJacopo Mondi 			.analog_crop = {
8163145efcdSJacopo Mondi 				.left	= 0,
8173145efcdSJacopo Mondi 				.top	= 4,
8183145efcdSJacopo Mondi 				.width	= 2624,
8193145efcdSJacopo Mondi 				.height	= 1944,
8203145efcdSJacopo Mondi 			},
8213145efcdSJacopo Mondi 			.crop = {
8223145efcdSJacopo Mondi 				.left	= 56,
8233145efcdSJacopo Mondi 				.top	= 6,
8243145efcdSJacopo Mondi 				.width	= 720,
8253145efcdSJacopo Mondi 				.height	= 576,
8263145efcdSJacopo Mondi 			},
8273145efcdSJacopo Mondi 			.htot		= 1896,
8283145efcdSJacopo Mondi 			.vblank_def	= 408,
8295113d5b3SJacopo Mondi 		},
8305113d5b3SJacopo Mondi 		.csi2_timings = {
8315113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
8325113d5b3SJacopo Mondi 			.analog_crop = {
8335113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
8345113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
8355113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
8365113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
8375113d5b3SJacopo Mondi 			},
8385113d5b3SJacopo Mondi 			.crop = {
8395113d5b3SJacopo Mondi 				.left	= 56,
8405113d5b3SJacopo Mondi 				.top	= 6,
8415113d5b3SJacopo Mondi 				.width	= 720,
8425113d5b3SJacopo Mondi 				.height	= 576,
8435113d5b3SJacopo Mondi 			},
8445113d5b3SJacopo Mondi 			.htot		= 1896,
845961bed9fSJacopo Mondi 			.vblank_def	= 1110,
8465113d5b3SJacopo Mondi 		},
847db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
848db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
84919f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
85019f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
8518409d017SJacopo Mondi 	}, {
8528409d017SJacopo Mondi 		/* 1024x768 */
8533145efcdSJacopo Mondi 		.id		= OV5640_MODE_XGA_1024_768,
8543145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
8553145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
8565113d5b3SJacopo Mondi 		.width		= 1024,
8575113d5b3SJacopo Mondi 		.height		= 768,
8585113d5b3SJacopo Mondi 		.dvp_timings = {
8593145efcdSJacopo Mondi 			.analog_crop = {
8603145efcdSJacopo Mondi 				.left	= 0,
8613145efcdSJacopo Mondi 				.top	= 4,
8623145efcdSJacopo Mondi 				.width	= 2624,
8633145efcdSJacopo Mondi 				.height	= 1944,
8643145efcdSJacopo Mondi 			},
8653145efcdSJacopo Mondi 			.crop = {
8663145efcdSJacopo Mondi 				.left	= 16,
8673145efcdSJacopo Mondi 				.top	= 6,
8683145efcdSJacopo Mondi 				.width	= 1024,
8693145efcdSJacopo Mondi 				.height	= 768,
8703145efcdSJacopo Mondi 			},
8713145efcdSJacopo Mondi 			.htot		= 1896,
8723145efcdSJacopo Mondi 			.vblank_def	= 312,
8735113d5b3SJacopo Mondi 		},
8745113d5b3SJacopo Mondi 		.csi2_timings = {
8755113d5b3SJacopo Mondi 			.analog_crop = {
8765113d5b3SJacopo Mondi 				.left	= 0,
8775113d5b3SJacopo Mondi 				.top	= 4,
8785113d5b3SJacopo Mondi 				.width	= OV5640_NATIVE_WIDTH,
8795113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
8805113d5b3SJacopo Mondi 			},
8815113d5b3SJacopo Mondi 			.crop = {
8825113d5b3SJacopo Mondi 				.left	= 16,
8835113d5b3SJacopo Mondi 				.top	= 6,
8845113d5b3SJacopo Mondi 				.width	= 1024,
8855113d5b3SJacopo Mondi 				.height	= 768,
8865113d5b3SJacopo Mondi 			},
8875113d5b3SJacopo Mondi 			.htot		= 1896,
888961bed9fSJacopo Mondi 			.vblank_def	= 918,
8895113d5b3SJacopo Mondi 		},
890db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
891db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
89219f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
89319f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
8948409d017SJacopo Mondi 	}, {
8958409d017SJacopo Mondi 		/* 1280x720 */
8963145efcdSJacopo Mondi 		.id		= OV5640_MODE_720P_1280_720,
8973145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
8983145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_124M,
8995113d5b3SJacopo Mondi 		.width		= 1280,
9005113d5b3SJacopo Mondi 		.height		= 720,
9015113d5b3SJacopo Mondi 		.dvp_timings = {
9023145efcdSJacopo Mondi 			.analog_crop = {
9033145efcdSJacopo Mondi 				.left	= 0,
9043145efcdSJacopo Mondi 				.top	= 250,
9053145efcdSJacopo Mondi 				.width	= 2624,
9063145efcdSJacopo Mondi 				.height	= 1456,
9073145efcdSJacopo Mondi 			},
9083145efcdSJacopo Mondi 			.crop = {
9093145efcdSJacopo Mondi 				.left	= 16,
9103145efcdSJacopo Mondi 				.top	= 4,
9113145efcdSJacopo Mondi 				.width	= 1280,
9123145efcdSJacopo Mondi 				.height	= 720,
9133145efcdSJacopo Mondi 			},
9143145efcdSJacopo Mondi 			.htot		= 1892,
9153145efcdSJacopo Mondi 			.vblank_def	= 20,
9165113d5b3SJacopo Mondi 		},
9175113d5b3SJacopo Mondi 		.csi2_timings = {
9185113d5b3SJacopo Mondi 			.analog_crop = {
9195113d5b3SJacopo Mondi 				.left	= 0,
9205113d5b3SJacopo Mondi 				.top	= 250,
9215113d5b3SJacopo Mondi 				.width	= 2624,
9225113d5b3SJacopo Mondi 				.height	= 1456,
9235113d5b3SJacopo Mondi 			},
9245113d5b3SJacopo Mondi 			.crop = {
9255113d5b3SJacopo Mondi 				.left	= 16,
9265113d5b3SJacopo Mondi 				.top	= 4,
9275113d5b3SJacopo Mondi 				.width	= 1280,
9285113d5b3SJacopo Mondi 				.height	= 720,
9295113d5b3SJacopo Mondi 			},
930961bed9fSJacopo Mondi 			.htot		= 1600,
931961bed9fSJacopo Mondi 			.vblank_def	= 560,
9325113d5b3SJacopo Mondi 		},
9333145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_720P_1280_720,
9343145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_720P_1280_720),
93519f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
93619f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
9378409d017SJacopo Mondi 	}, {
9388409d017SJacopo Mondi 		/* 1920x1080 */
9393145efcdSJacopo Mondi 		.id		= OV5640_MODE_1080P_1920_1080,
9403145efcdSJacopo Mondi 		.dn_mode	= SCALING,
9413145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_148M,
9425113d5b3SJacopo Mondi 		.width		= 1920,
9435113d5b3SJacopo Mondi 		.height		= 1080,
9445113d5b3SJacopo Mondi 		.dvp_timings = {
9453145efcdSJacopo Mondi 			.analog_crop = {
9463145efcdSJacopo Mondi 				.left	= 336,
9473145efcdSJacopo Mondi 				.top	= 434,
9483145efcdSJacopo Mondi 				.width	= 1952,
9493145efcdSJacopo Mondi 				.height	= 1088,
9503145efcdSJacopo Mondi 			},
9513145efcdSJacopo Mondi 			.crop = {
9523145efcdSJacopo Mondi 				.left	= 16,
9533145efcdSJacopo Mondi 				.top	= 4,
9543145efcdSJacopo Mondi 				.width	= 1920,
9553145efcdSJacopo Mondi 				.height	= 1080,
9563145efcdSJacopo Mondi 			},
9573145efcdSJacopo Mondi 			.htot		= 2500,
9583145efcdSJacopo Mondi 			.vblank_def	= 40,
9595113d5b3SJacopo Mondi 		},
9605113d5b3SJacopo Mondi 		.csi2_timings = {
9615113d5b3SJacopo Mondi 			/* Crop the full valid pixel array in the center. */
9625113d5b3SJacopo Mondi 			.analog_crop = {
9635113d5b3SJacopo Mondi 				.left	= 336,
9645113d5b3SJacopo Mondi 				.top	= 434,
9655113d5b3SJacopo Mondi 				.width	= 1952,
9665113d5b3SJacopo Mondi 				.height	= 1088,
9675113d5b3SJacopo Mondi 			},
9685113d5b3SJacopo Mondi 			/* Maintain a larger processing margins. */
9695113d5b3SJacopo Mondi 			.crop = {
9705113d5b3SJacopo Mondi 				.left	= 16,
9715113d5b3SJacopo Mondi 				.top	= 4,
9725113d5b3SJacopo Mondi 				.width	= 1920,
9735113d5b3SJacopo Mondi 				.height	= 1080,
9745113d5b3SJacopo Mondi 			},
975961bed9fSJacopo Mondi 			.htot		= 2234,
976961bed9fSJacopo Mondi 			.vblank_def	= 24,
9775113d5b3SJacopo Mondi 		},
9783145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_1080P_1920_1080,
9793145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_1080P_1920_1080),
98019f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
98119f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
9828409d017SJacopo Mondi 	}, {
9838409d017SJacopo Mondi 		/* 2592x1944 */
9843145efcdSJacopo Mondi 		.id		= OV5640_MODE_QSXGA_2592_1944,
9853145efcdSJacopo Mondi 		.dn_mode	= SCALING,
9863145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_168M,
9875113d5b3SJacopo Mondi 		.width		= OV5640_PIXEL_ARRAY_WIDTH,
9885113d5b3SJacopo Mondi 		.height		= OV5640_PIXEL_ARRAY_HEIGHT,
9895113d5b3SJacopo Mondi 		.dvp_timings = {
9903145efcdSJacopo Mondi 			.analog_crop = {
9913145efcdSJacopo Mondi 				.left	= 0,
9923145efcdSJacopo Mondi 				.top	= 0,
9933145efcdSJacopo Mondi 				.width	= 2624,
9943145efcdSJacopo Mondi 				.height	= 1952,
9953145efcdSJacopo Mondi 			},
9963145efcdSJacopo Mondi 			.crop = {
9973145efcdSJacopo Mondi 				.left	= 16,
9983145efcdSJacopo Mondi 				.top	= 4,
9993145efcdSJacopo Mondi 				.width	= 2592,
10003145efcdSJacopo Mondi 				.height	= 1944,
10013145efcdSJacopo Mondi 			},
10023145efcdSJacopo Mondi 			.htot		= 2844,
10033145efcdSJacopo Mondi 			.vblank_def	= 24,
10045113d5b3SJacopo Mondi 		},
10055113d5b3SJacopo Mondi 		.csi2_timings = {
10065113d5b3SJacopo Mondi 			/* Give more processing margin to full resolution. */
10075113d5b3SJacopo Mondi 			.analog_crop = {
10085113d5b3SJacopo Mondi 				.left	= 0,
10095113d5b3SJacopo Mondi 				.top	= 0,
10105113d5b3SJacopo Mondi 				.width	= OV5640_NATIVE_WIDTH,
10115113d5b3SJacopo Mondi 				.height	= 1952,
10125113d5b3SJacopo Mondi 			},
10135113d5b3SJacopo Mondi 			.crop = {
10145113d5b3SJacopo Mondi 				.left	= 16,
10155113d5b3SJacopo Mondi 				.top	= 4,
10165113d5b3SJacopo Mondi 				.width	= 2592,
10175113d5b3SJacopo Mondi 				.height	= 1944,
10185113d5b3SJacopo Mondi 			},
10195113d5b3SJacopo Mondi 			.htot		= 2844,
10205113d5b3SJacopo Mondi 			.vblank_def	= 24,
10215113d5b3SJacopo Mondi 		},
10223145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_QSXGA_2592_1944,
10233145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_QSXGA_2592_1944),
102419f2e3e6SHugues Fruchet 		.max_fps	= OV5640_15_FPS,
102519f2e3e6SHugues Fruchet 		.def_fps	= OV5640_15_FPS
10268409d017SJacopo Mondi 	},
102719a81c14SSteve Longerbeam };
102819a81c14SSteve Longerbeam 
10292de6bb97SJacopo Mondi static const struct ov5640_timings *
10302de6bb97SJacopo Mondi ov5640_timings(const struct ov5640_dev *sensor,
10312de6bb97SJacopo Mondi 	       const struct ov5640_mode_info *mode)
10322de6bb97SJacopo Mondi {
10332de6bb97SJacopo Mondi 	if (ov5640_is_csi2(sensor))
10342de6bb97SJacopo Mondi 		return &mode->csi2_timings;
10352de6bb97SJacopo Mondi 
10362de6bb97SJacopo Mondi 	return &mode->dvp_timings;
10372de6bb97SJacopo Mondi }
10382de6bb97SJacopo Mondi 
103919a81c14SSteve Longerbeam static int ov5640_init_slave_id(struct ov5640_dev *sensor)
104019a81c14SSteve Longerbeam {
104119a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
104219a81c14SSteve Longerbeam 	struct i2c_msg msg;
104319a81c14SSteve Longerbeam 	u8 buf[3];
104419a81c14SSteve Longerbeam 	int ret;
104519a81c14SSteve Longerbeam 
104619a81c14SSteve Longerbeam 	if (client->addr == OV5640_DEFAULT_SLAVE_ID)
104719a81c14SSteve Longerbeam 		return 0;
104819a81c14SSteve Longerbeam 
104919a81c14SSteve Longerbeam 	buf[0] = OV5640_REG_SLAVE_ID >> 8;
105019a81c14SSteve Longerbeam 	buf[1] = OV5640_REG_SLAVE_ID & 0xff;
105119a81c14SSteve Longerbeam 	buf[2] = client->addr << 1;
105219a81c14SSteve Longerbeam 
105319a81c14SSteve Longerbeam 	msg.addr = OV5640_DEFAULT_SLAVE_ID;
105419a81c14SSteve Longerbeam 	msg.flags = 0;
105519a81c14SSteve Longerbeam 	msg.buf = buf;
105619a81c14SSteve Longerbeam 	msg.len = sizeof(buf);
105719a81c14SSteve Longerbeam 
105819a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, &msg, 1);
105919a81c14SSteve Longerbeam 	if (ret < 0) {
106019a81c14SSteve Longerbeam 		dev_err(&client->dev, "%s: failed with %d\n", __func__, ret);
106119a81c14SSteve Longerbeam 		return ret;
106219a81c14SSteve Longerbeam 	}
106319a81c14SSteve Longerbeam 
106419a81c14SSteve Longerbeam 	return 0;
106519a81c14SSteve Longerbeam }
106619a81c14SSteve Longerbeam 
106719a81c14SSteve Longerbeam static int ov5640_write_reg(struct ov5640_dev *sensor, u16 reg, u8 val)
106819a81c14SSteve Longerbeam {
106919a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
107019a81c14SSteve Longerbeam 	struct i2c_msg msg;
107119a81c14SSteve Longerbeam 	u8 buf[3];
107219a81c14SSteve Longerbeam 	int ret;
107319a81c14SSteve Longerbeam 
107419a81c14SSteve Longerbeam 	buf[0] = reg >> 8;
107519a81c14SSteve Longerbeam 	buf[1] = reg & 0xff;
107619a81c14SSteve Longerbeam 	buf[2] = val;
107719a81c14SSteve Longerbeam 
107819a81c14SSteve Longerbeam 	msg.addr = client->addr;
107919a81c14SSteve Longerbeam 	msg.flags = client->flags;
108019a81c14SSteve Longerbeam 	msg.buf = buf;
108119a81c14SSteve Longerbeam 	msg.len = sizeof(buf);
108219a81c14SSteve Longerbeam 
108319a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, &msg, 1);
108419a81c14SSteve Longerbeam 	if (ret < 0) {
10853924c623SHugues Fruchet 		dev_err(&client->dev, "%s: error: reg=%x, val=%x\n",
108619a81c14SSteve Longerbeam 			__func__, reg, val);
108719a81c14SSteve Longerbeam 		return ret;
108819a81c14SSteve Longerbeam 	}
108919a81c14SSteve Longerbeam 
109019a81c14SSteve Longerbeam 	return 0;
109119a81c14SSteve Longerbeam }
109219a81c14SSteve Longerbeam 
109319a81c14SSteve Longerbeam static int ov5640_read_reg(struct ov5640_dev *sensor, u16 reg, u8 *val)
109419a81c14SSteve Longerbeam {
109519a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
109619a81c14SSteve Longerbeam 	struct i2c_msg msg[2];
109719a81c14SSteve Longerbeam 	u8 buf[2];
109819a81c14SSteve Longerbeam 	int ret;
109919a81c14SSteve Longerbeam 
110019a81c14SSteve Longerbeam 	buf[0] = reg >> 8;
110119a81c14SSteve Longerbeam 	buf[1] = reg & 0xff;
110219a81c14SSteve Longerbeam 
110319a81c14SSteve Longerbeam 	msg[0].addr = client->addr;
110419a81c14SSteve Longerbeam 	msg[0].flags = client->flags;
110519a81c14SSteve Longerbeam 	msg[0].buf = buf;
110619a81c14SSteve Longerbeam 	msg[0].len = sizeof(buf);
110719a81c14SSteve Longerbeam 
110819a81c14SSteve Longerbeam 	msg[1].addr = client->addr;
110919a81c14SSteve Longerbeam 	msg[1].flags = client->flags | I2C_M_RD;
111019a81c14SSteve Longerbeam 	msg[1].buf = buf;
111119a81c14SSteve Longerbeam 	msg[1].len = 1;
111219a81c14SSteve Longerbeam 
111319a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, msg, 2);
11143924c623SHugues Fruchet 	if (ret < 0) {
11153924c623SHugues Fruchet 		dev_err(&client->dev, "%s: error: reg=%x\n",
11163924c623SHugues Fruchet 			__func__, reg);
111719a81c14SSteve Longerbeam 		return ret;
11183924c623SHugues Fruchet 	}
111919a81c14SSteve Longerbeam 
112019a81c14SSteve Longerbeam 	*val = buf[0];
112119a81c14SSteve Longerbeam 	return 0;
112219a81c14SSteve Longerbeam }
112319a81c14SSteve Longerbeam 
112419a81c14SSteve Longerbeam static int ov5640_read_reg16(struct ov5640_dev *sensor, u16 reg, u16 *val)
112519a81c14SSteve Longerbeam {
112619a81c14SSteve Longerbeam 	u8 hi, lo;
112719a81c14SSteve Longerbeam 	int ret;
112819a81c14SSteve Longerbeam 
112919a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg, &hi);
113019a81c14SSteve Longerbeam 	if (ret)
113119a81c14SSteve Longerbeam 		return ret;
113219a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg + 1, &lo);
113319a81c14SSteve Longerbeam 	if (ret)
113419a81c14SSteve Longerbeam 		return ret;
113519a81c14SSteve Longerbeam 
113619a81c14SSteve Longerbeam 	*val = ((u16)hi << 8) | (u16)lo;
113719a81c14SSteve Longerbeam 	return 0;
113819a81c14SSteve Longerbeam }
113919a81c14SSteve Longerbeam 
114019a81c14SSteve Longerbeam static int ov5640_write_reg16(struct ov5640_dev *sensor, u16 reg, u16 val)
114119a81c14SSteve Longerbeam {
114219a81c14SSteve Longerbeam 	int ret;
114319a81c14SSteve Longerbeam 
114419a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, reg, val >> 8);
114519a81c14SSteve Longerbeam 	if (ret)
114619a81c14SSteve Longerbeam 		return ret;
114719a81c14SSteve Longerbeam 
114819a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, reg + 1, val & 0xff);
114919a81c14SSteve Longerbeam }
115019a81c14SSteve Longerbeam 
115119a81c14SSteve Longerbeam static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg,
115219a81c14SSteve Longerbeam 			  u8 mask, u8 val)
115319a81c14SSteve Longerbeam {
115419a81c14SSteve Longerbeam 	u8 readval;
115519a81c14SSteve Longerbeam 	int ret;
115619a81c14SSteve Longerbeam 
115719a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg, &readval);
115819a81c14SSteve Longerbeam 	if (ret)
115919a81c14SSteve Longerbeam 		return ret;
116019a81c14SSteve Longerbeam 
116119a81c14SSteve Longerbeam 	readval &= ~mask;
116219a81c14SSteve Longerbeam 	val &= mask;
116319a81c14SSteve Longerbeam 	val |= readval;
116419a81c14SSteve Longerbeam 
116519a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, reg, val);
116619a81c14SSteve Longerbeam }
116719a81c14SSteve Longerbeam 
1168aa288248SMaxime Ripard /*
1169aa288248SMaxime Ripard  * After trying the various combinations, reading various
1170f8a7647dSMauro Carvalho Chehab  * documentations spread around the net, and from the various
1171aa288248SMaxime Ripard  * feedback, the clock tree is probably as follows:
1172aa288248SMaxime Ripard  *
1173aa288248SMaxime Ripard  *   +--------------+
1174aa288248SMaxime Ripard  *   |  Ext. Clock  |
1175aa288248SMaxime Ripard  *   +-+------------+
1176aa288248SMaxime Ripard  *     |  +----------+
1177aa288248SMaxime Ripard  *     +->|   PLL1   | - reg 0x3036, for the multiplier
1178aa288248SMaxime Ripard  *        +-+--------+ - reg 0x3037, bits 0-3 for the pre-divider
1179aa288248SMaxime Ripard  *          |  +--------------+
1180aa288248SMaxime Ripard  *          +->| System Clock |  - reg 0x3035, bits 4-7
1181aa288248SMaxime Ripard  *             +-+------------+
1182aa288248SMaxime Ripard  *               |  +--------------+
1183aa288248SMaxime Ripard  *               +->| MIPI Divider | - reg 0x3035, bits 0-3
1184aa288248SMaxime Ripard  *               |  +-+------------+
1185aa288248SMaxime Ripard  *               |    +----------------> MIPI SCLK
1186aa288248SMaxime Ripard  *               |    +  +-----+
1187aa288248SMaxime Ripard  *               |    +->| / 2 |-------> MIPI BIT CLK
1188aa288248SMaxime Ripard  *               |       +-----+
1189aa288248SMaxime Ripard  *               |  +--------------+
1190aa288248SMaxime Ripard  *               +->| PLL Root Div | - reg 0x3037, bit 4
1191aa288248SMaxime Ripard  *                  +-+------------+
1192aa288248SMaxime Ripard  *                    |  +---------+
11934c85f628SPaul Kocialkowski  *                    +->| Bit Div | - reg 0x3034, bits 0-3
1194aa288248SMaxime Ripard  *                       +-+-------+
1195aa288248SMaxime Ripard  *                         |  +-------------+
1196aa288248SMaxime Ripard  *                         +->| SCLK Div    | - reg 0x3108, bits 0-1
1197aa288248SMaxime Ripard  *                         |  +-+-----------+
1198aa288248SMaxime Ripard  *                         |    +---------------> SCLK
1199aa288248SMaxime Ripard  *                         |  +-------------+
1200aa288248SMaxime Ripard  *                         +->| SCLK 2X Div | - reg 0x3108, bits 2-3
1201aa288248SMaxime Ripard  *                         |  +-+-----------+
1202aa288248SMaxime Ripard  *                         |    +---------------> SCLK 2X
1203aa288248SMaxime Ripard  *                         |  +-------------+
1204aa288248SMaxime Ripard  *                         +->| PCLK Div    | - reg 0x3108, bits 4-5
1205aa288248SMaxime Ripard  *                            ++------------+
1206aa288248SMaxime Ripard  *                             +  +-----------+
1207aa288248SMaxime Ripard  *                             +->|   P_DIV   | - reg 0x3035, bits 0-3
1208aa288248SMaxime Ripard  *                                +-----+-----+
1209aa288248SMaxime Ripard  *                                       +------------> PCLK
1210aa288248SMaxime Ripard  *
12116c957ed7SJacopo Mondi  * There seems to be also constraints:
1212aa288248SMaxime Ripard  *  - the PLL pre-divider output rate should be in the 4-27MHz range
1213aa288248SMaxime Ripard  *  - the PLL multiplier output rate should be in the 500-1000MHz range
1214aa288248SMaxime Ripard  *  - PCLK >= SCLK * 2 in YUV, >= SCLK in Raw or JPEG
1215aa288248SMaxime Ripard  */
1216aa288248SMaxime Ripard 
1217aa288248SMaxime Ripard /*
1218aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1219aa288248SMaxime Ripard  * set to 3 in the vendor kernels.
1220aa288248SMaxime Ripard  */
1221aa288248SMaxime Ripard #define OV5640_PLL_PREDIV	3
1222aa288248SMaxime Ripard 
1223aa288248SMaxime Ripard #define OV5640_PLL_MULT_MIN	4
1224aa288248SMaxime Ripard #define OV5640_PLL_MULT_MAX	252
1225aa288248SMaxime Ripard 
1226aa288248SMaxime Ripard /*
1227aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 16, but the value is
1228aa288248SMaxime Ripard  * always set to either 1 or 2 in the vendor kernels.
1229aa288248SMaxime Ripard  */
1230aa288248SMaxime Ripard #define OV5640_SYSDIV_MIN	1
1231aa288248SMaxime Ripard #define OV5640_SYSDIV_MAX	16
1232aa288248SMaxime Ripard 
1233aa288248SMaxime Ripard /*
1234aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 2, but the value is always
1235aa288248SMaxime Ripard  * set to 2 in the vendor kernels.
1236aa288248SMaxime Ripard  */
1237aa288248SMaxime Ripard #define OV5640_PLL_ROOT_DIV			2
1238aa288248SMaxime Ripard #define OV5640_PLL_CTRL3_PLL_ROOT_DIV_2		BIT(4)
1239aa288248SMaxime Ripard 
1240aa288248SMaxime Ripard /*
1241aa288248SMaxime Ripard  * We only supports 8-bit formats at the moment
1242aa288248SMaxime Ripard  */
1243aa288248SMaxime Ripard #define OV5640_BIT_DIV				2
1244aa288248SMaxime Ripard #define OV5640_PLL_CTRL0_MIPI_MODE_8BIT		0x08
1245aa288248SMaxime Ripard 
1246aa288248SMaxime Ripard /*
1247aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1248aa288248SMaxime Ripard  * set to 2 in the vendor kernels.
1249aa288248SMaxime Ripard  */
1250aa288248SMaxime Ripard #define OV5640_SCLK_ROOT_DIV	2
1251aa288248SMaxime Ripard 
1252aa288248SMaxime Ripard /*
1253aa288248SMaxime Ripard  * This is hardcoded so that the consistency is maintained between SCLK and
1254aa288248SMaxime Ripard  * SCLK 2x.
1255aa288248SMaxime Ripard  */
1256aa288248SMaxime Ripard #define OV5640_SCLK2X_ROOT_DIV (OV5640_SCLK_ROOT_DIV / 2)
1257aa288248SMaxime Ripard 
1258aa288248SMaxime Ripard /*
1259aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1260aa288248SMaxime Ripard  * set to 1 in the vendor kernels.
1261aa288248SMaxime Ripard  */
1262aa288248SMaxime Ripard #define OV5640_PCLK_ROOT_DIV			1
1263aa288248SMaxime Ripard #define OV5640_PLL_SYS_ROOT_DIVIDER_BYPASS	0x00
1264aa288248SMaxime Ripard 
1265aa288248SMaxime Ripard static unsigned long ov5640_compute_sys_clk(struct ov5640_dev *sensor,
1266aa288248SMaxime Ripard 					    u8 pll_prediv, u8 pll_mult,
1267aa288248SMaxime Ripard 					    u8 sysdiv)
1268aa288248SMaxime Ripard {
1269aa288248SMaxime Ripard 	unsigned long sysclk = sensor->xclk_freq / pll_prediv * pll_mult;
1270aa288248SMaxime Ripard 
1271aa288248SMaxime Ripard 	/* PLL1 output cannot exceed 1GHz. */
1272aa288248SMaxime Ripard 	if (sysclk / 1000000 > 1000)
1273aa288248SMaxime Ripard 		return 0;
1274aa288248SMaxime Ripard 
1275aa288248SMaxime Ripard 	return sysclk / sysdiv;
1276aa288248SMaxime Ripard }
1277aa288248SMaxime Ripard 
1278aa288248SMaxime Ripard static unsigned long ov5640_calc_sys_clk(struct ov5640_dev *sensor,
1279aa288248SMaxime Ripard 					 unsigned long rate,
1280aa288248SMaxime Ripard 					 u8 *pll_prediv, u8 *pll_mult,
1281aa288248SMaxime Ripard 					 u8 *sysdiv)
1282aa288248SMaxime Ripard {
1283aa288248SMaxime Ripard 	unsigned long best = ~0;
1284aa288248SMaxime Ripard 	u8 best_sysdiv = 1, best_mult = 1;
1285aa288248SMaxime Ripard 	u8 _sysdiv, _pll_mult;
1286aa288248SMaxime Ripard 
1287aa288248SMaxime Ripard 	for (_sysdiv = OV5640_SYSDIV_MIN;
1288aa288248SMaxime Ripard 	     _sysdiv <= OV5640_SYSDIV_MAX;
1289aa288248SMaxime Ripard 	     _sysdiv++) {
1290aa288248SMaxime Ripard 		for (_pll_mult = OV5640_PLL_MULT_MIN;
1291aa288248SMaxime Ripard 		     _pll_mult <= OV5640_PLL_MULT_MAX;
1292aa288248SMaxime Ripard 		     _pll_mult++) {
1293aa288248SMaxime Ripard 			unsigned long _rate;
1294aa288248SMaxime Ripard 
1295aa288248SMaxime Ripard 			/*
1296aa288248SMaxime Ripard 			 * The PLL multiplier cannot be odd if above
1297aa288248SMaxime Ripard 			 * 127.
1298aa288248SMaxime Ripard 			 */
1299aa288248SMaxime Ripard 			if (_pll_mult > 127 && (_pll_mult % 2))
1300aa288248SMaxime Ripard 				continue;
1301aa288248SMaxime Ripard 
1302aa288248SMaxime Ripard 			_rate = ov5640_compute_sys_clk(sensor,
1303aa288248SMaxime Ripard 						       OV5640_PLL_PREDIV,
1304aa288248SMaxime Ripard 						       _pll_mult, _sysdiv);
1305aa288248SMaxime Ripard 
1306aa288248SMaxime Ripard 			/*
1307aa288248SMaxime Ripard 			 * We have reached the maximum allowed PLL1 output,
1308aa288248SMaxime Ripard 			 * increase sysdiv.
1309aa288248SMaxime Ripard 			 */
13102e3df204SAdam Ford 			if (!_rate)
1311aa288248SMaxime Ripard 				break;
1312aa288248SMaxime Ripard 
1313aa288248SMaxime Ripard 			/*
1314aa288248SMaxime Ripard 			 * Prefer rates above the expected clock rate than
1315aa288248SMaxime Ripard 			 * below, even if that means being less precise.
1316aa288248SMaxime Ripard 			 */
1317aa288248SMaxime Ripard 			if (_rate < rate)
1318aa288248SMaxime Ripard 				continue;
1319aa288248SMaxime Ripard 
1320aa288248SMaxime Ripard 			if (abs(rate - _rate) < abs(rate - best)) {
1321aa288248SMaxime Ripard 				best = _rate;
1322aa288248SMaxime Ripard 				best_sysdiv = _sysdiv;
1323aa288248SMaxime Ripard 				best_mult = _pll_mult;
1324aa288248SMaxime Ripard 			}
1325aa288248SMaxime Ripard 
1326aa288248SMaxime Ripard 			if (_rate == rate)
1327aa288248SMaxime Ripard 				goto out;
1328aa288248SMaxime Ripard 		}
1329aa288248SMaxime Ripard 	}
1330aa288248SMaxime Ripard 
1331aa288248SMaxime Ripard out:
1332aa288248SMaxime Ripard 	*sysdiv = best_sysdiv;
1333aa288248SMaxime Ripard 	*pll_prediv = OV5640_PLL_PREDIV;
1334aa288248SMaxime Ripard 	*pll_mult = best_mult;
1335aa288248SMaxime Ripard 
1336aa288248SMaxime Ripard 	return best;
1337aa288248SMaxime Ripard }
1338aa288248SMaxime Ripard 
1339aa288248SMaxime Ripard /*
1340aa288248SMaxime Ripard  * ov5640_set_mipi_pclk() - Calculate the clock tree configuration values
1341aa288248SMaxime Ripard  *			    for the MIPI CSI-2 output.
1342aa288248SMaxime Ripard  */
13436c957ed7SJacopo Mondi static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor)
1344aa288248SMaxime Ripard {
13456c957ed7SJacopo Mondi 	u8 bit_div, mipi_div, pclk_div, sclk_div, sclk2x_div, root_div;
1346aa288248SMaxime Ripard 	u8 prediv, mult, sysdiv;
13476c957ed7SJacopo Mondi 	unsigned long link_freq;
13486c957ed7SJacopo Mondi 	unsigned long sysclk;
13496c957ed7SJacopo Mondi 	u8 pclk_period;
13506c957ed7SJacopo Mondi 	u32 sample_rate;
13516c957ed7SJacopo Mondi 	u32 num_lanes;
1352aa288248SMaxime Ripard 	int ret;
1353aa288248SMaxime Ripard 
13546c957ed7SJacopo Mondi 	/* Use the link freq computed at ov5640_update_pixel_rate() time. */
13556c957ed7SJacopo Mondi 	link_freq = sensor->current_link_freq;
13566c957ed7SJacopo Mondi 
1357aa288248SMaxime Ripard 	/*
13586c957ed7SJacopo Mondi 	 * - mipi_div - Additional divider for the MIPI lane clock.
13596c957ed7SJacopo Mondi 	 *
13606c957ed7SJacopo Mondi 	 * Higher link frequencies would make sysclk > 1GHz.
13616c957ed7SJacopo Mondi 	 * Keep the sysclk low and do not divide in the MIPI domain.
1362aa288248SMaxime Ripard 	 */
13636c957ed7SJacopo Mondi 	if (link_freq > OV5640_LINK_RATE_MAX)
13646c957ed7SJacopo Mondi 		mipi_div = 1;
1365aa288248SMaxime Ripard 	else
13666c957ed7SJacopo Mondi 		mipi_div = 2;
1367aa288248SMaxime Ripard 
13686c957ed7SJacopo Mondi 	sysclk = link_freq * mipi_div;
13696c957ed7SJacopo Mondi 	ov5640_calc_sys_clk(sensor, sysclk, &prediv, &mult, &sysdiv);
1370aa288248SMaxime Ripard 
13716c957ed7SJacopo Mondi 	/*
13726c957ed7SJacopo Mondi 	 * Adjust PLL parameters to maintain the MIPI_SCLK-to-PCLK ratio.
13736c957ed7SJacopo Mondi 	 *
13746c957ed7SJacopo Mondi 	 * - root_div = 2 (fixed)
13756c957ed7SJacopo Mondi 	 * - bit_div : MIPI 8-bit = 2; MIPI 10-bit = 2.5
13766c957ed7SJacopo Mondi 	 * - pclk_div = 1 (fixed)
13776c957ed7SJacopo Mondi 	 * - p_div  = (2 lanes ? mipi_div : 2 * mipi_div)
13786c957ed7SJacopo Mondi 	 *
13796c957ed7SJacopo Mondi 	 * This results in the following MIPI_SCLK depending on the number
13806c957ed7SJacopo Mondi 	 * of lanes:
13816c957ed7SJacopo Mondi 	 *
13826c957ed7SJacopo Mondi 	 * - 2 lanes: MIPI_SCLK = (4 or 5) * PCLK
13836c957ed7SJacopo Mondi 	 * - 1 lanes: MIPI_SCLK = (8 or 10) * PCLK
13846c957ed7SJacopo Mondi 	 */
13856c957ed7SJacopo Mondi 	root_div = OV5640_PLL_CTRL3_PLL_ROOT_DIV_2;
13866c957ed7SJacopo Mondi 	bit_div =  OV5640_PLL_CTRL0_MIPI_MODE_8BIT;
13876c957ed7SJacopo Mondi 	pclk_div = ilog2(OV5640_PCLK_ROOT_DIV);
1388aa288248SMaxime Ripard 
13896c957ed7SJacopo Mondi 	/*
13906c957ed7SJacopo Mondi 	 * Scaler clock:
13916c957ed7SJacopo Mondi 	 * - YUV: PCLK >= 2 * SCLK
13926c957ed7SJacopo Mondi 	 * - RAW or JPEG: PCLK >= SCLK
13936c957ed7SJacopo Mondi 	 * - sclk2x_div = sclk_div / 2
13946c957ed7SJacopo Mondi 	 */
13956c957ed7SJacopo Mondi 	sclk_div = ilog2(OV5640_SCLK_ROOT_DIV);
13966c957ed7SJacopo Mondi 	sclk2x_div = ilog2(OV5640_SCLK2X_ROOT_DIV);
13976c957ed7SJacopo Mondi 
13986c957ed7SJacopo Mondi 	/*
13996c957ed7SJacopo Mondi 	 * Set the pixel clock period expressed in ns with 1-bit decimal
14006c957ed7SJacopo Mondi 	 * (0x01=0.5ns).
14016c957ed7SJacopo Mondi 	 *
14026c957ed7SJacopo Mondi 	 * The register is very briefly documented. In the OV5645 datasheet it
14036c957ed7SJacopo Mondi 	 * is described as (2 * pclk period), and from testing it seems the
14046c957ed7SJacopo Mondi 	 * actual definition is 2 * 8-bit sample period.
14056c957ed7SJacopo Mondi 	 *
14066c957ed7SJacopo Mondi 	 * 2 * sample_period = (mipi_clk * 2 * num_lanes / bpp) * (bpp / 8) / 2
14076c957ed7SJacopo Mondi 	 */
14086c957ed7SJacopo Mondi 	num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes;
14096c957ed7SJacopo Mondi 	sample_rate = (link_freq * mipi_div * num_lanes * 2) / 16;
14106c957ed7SJacopo Mondi 	pclk_period = 2000000000UL / sample_rate;
14116c957ed7SJacopo Mondi 
14126c957ed7SJacopo Mondi 	/* Program the clock tree registers. */
14136c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0, 0x0f, bit_div);
14146c957ed7SJacopo Mondi 	if (ret)
14156c957ed7SJacopo Mondi 		return ret;
14166c957ed7SJacopo Mondi 
14176c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, 0xff,
14186c957ed7SJacopo Mondi 			     (sysdiv << 4) | mipi_div);
1419aa288248SMaxime Ripard 	if (ret)
1420aa288248SMaxime Ripard 		return ret;
1421aa288248SMaxime Ripard 
1422aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2, 0xff, mult);
1423aa288248SMaxime Ripard 	if (ret)
1424aa288248SMaxime Ripard 		return ret;
1425aa288248SMaxime Ripard 
14266c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3, 0x1f,
14276c957ed7SJacopo Mondi 			     root_div | prediv);
1428aa288248SMaxime Ripard 	if (ret)
1429aa288248SMaxime Ripard 		return ret;
1430aa288248SMaxime Ripard 
14316c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
14326c957ed7SJacopo Mondi 			     (pclk_div << 4) | (sclk2x_div << 2) | sclk_div);
14336c957ed7SJacopo Mondi 	if (ret)
14346c957ed7SJacopo Mondi 		return ret;
14356c957ed7SJacopo Mondi 
14366c957ed7SJacopo Mondi 	return ov5640_write_reg(sensor, OV5640_REG_PCLK_PERIOD, pclk_period);
14376c957ed7SJacopo Mondi }
14386c957ed7SJacopo Mondi 
14396c957ed7SJacopo Mondi static u32 ov5640_calc_pixel_rate(struct ov5640_dev *sensor)
14406c957ed7SJacopo Mondi {
14413145efcdSJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
14425113d5b3SJacopo Mondi 	const struct ov5640_timings *timings = &mode->dvp_timings;
14436c957ed7SJacopo Mondi 	u32 rate;
14446c957ed7SJacopo Mondi 
14455113d5b3SJacopo Mondi 	rate = timings->htot * (timings->crop.height + timings->vblank_def);
14466c957ed7SJacopo Mondi 	rate *= ov5640_framerates[sensor->current_fr];
14476c957ed7SJacopo Mondi 
14486c957ed7SJacopo Mondi 	return rate;
1449aa288248SMaxime Ripard }
1450aa288248SMaxime Ripard 
1451aa288248SMaxime Ripard static unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor,
1452aa288248SMaxime Ripard 				      unsigned long rate,
1453aa288248SMaxime Ripard 				      u8 *pll_prediv, u8 *pll_mult, u8 *sysdiv,
1454aa288248SMaxime Ripard 				      u8 *pll_rdiv, u8 *bit_div, u8 *pclk_div)
1455aa288248SMaxime Ripard {
1456aa288248SMaxime Ripard 	unsigned long _rate = rate * OV5640_PLL_ROOT_DIV * OV5640_BIT_DIV *
1457aa288248SMaxime Ripard 				OV5640_PCLK_ROOT_DIV;
1458aa288248SMaxime Ripard 
1459aa288248SMaxime Ripard 	_rate = ov5640_calc_sys_clk(sensor, _rate, pll_prediv, pll_mult,
1460aa288248SMaxime Ripard 				    sysdiv);
1461aa288248SMaxime Ripard 	*pll_rdiv = OV5640_PLL_ROOT_DIV;
1462aa288248SMaxime Ripard 	*bit_div = OV5640_BIT_DIV;
1463aa288248SMaxime Ripard 	*pclk_div = OV5640_PCLK_ROOT_DIV;
1464aa288248SMaxime Ripard 
1465aa288248SMaxime Ripard 	return _rate / *pll_rdiv / *bit_div / *pclk_div;
1466aa288248SMaxime Ripard }
1467aa288248SMaxime Ripard 
14686c957ed7SJacopo Mondi static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor)
1469aa288248SMaxime Ripard {
1470aa288248SMaxime Ripard 	u8 prediv, mult, sysdiv, pll_rdiv, bit_div, pclk_div;
14716c957ed7SJacopo Mondi 	u32 rate;
1472aa288248SMaxime Ripard 	int ret;
1473aa288248SMaxime Ripard 
14746c957ed7SJacopo Mondi 	rate = ov5640_calc_pixel_rate(sensor);
14756c957ed7SJacopo Mondi 	rate *= ov5640_code_to_bpp(sensor->fmt.code);
14766c957ed7SJacopo Mondi 	rate /= sensor->ep.bus.parallel.bus_width;
14776c957ed7SJacopo Mondi 
1478aa288248SMaxime Ripard 	ov5640_calc_pclk(sensor, rate, &prediv, &mult, &sysdiv, &pll_rdiv,
1479aa288248SMaxime Ripard 			 &bit_div, &pclk_div);
1480aa288248SMaxime Ripard 
1481aa288248SMaxime Ripard 	if (bit_div == 2)
1482aa288248SMaxime Ripard 		bit_div = 8;
1483aa288248SMaxime Ripard 
1484aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0,
1485aa288248SMaxime Ripard 			     0x0f, bit_div);
1486aa288248SMaxime Ripard 	if (ret)
1487aa288248SMaxime Ripard 		return ret;
1488aa288248SMaxime Ripard 
1489aa288248SMaxime Ripard 	/*
1490aa288248SMaxime Ripard 	 * We need to set sysdiv according to the clock, and to clear
1491aa288248SMaxime Ripard 	 * the MIPI divider.
1492aa288248SMaxime Ripard 	 */
1493aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1,
1494aa288248SMaxime Ripard 			     0xff, sysdiv << 4);
1495aa288248SMaxime Ripard 	if (ret)
1496aa288248SMaxime Ripard 		return ret;
1497aa288248SMaxime Ripard 
1498aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2,
1499aa288248SMaxime Ripard 			     0xff, mult);
1500aa288248SMaxime Ripard 	if (ret)
1501aa288248SMaxime Ripard 		return ret;
1502aa288248SMaxime Ripard 
1503aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3,
1504aa288248SMaxime Ripard 			     0x1f, prediv | ((pll_rdiv - 1) << 4));
1505aa288248SMaxime Ripard 	if (ret)
1506aa288248SMaxime Ripard 		return ret;
1507aa288248SMaxime Ripard 
1508aa288248SMaxime Ripard 	return ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x30,
1509aa288248SMaxime Ripard 			      (ilog2(pclk_div) << 4));
1510aa288248SMaxime Ripard }
1511aa288248SMaxime Ripard 
15127cb013b1SChen-Yu Tsai /* set JPEG framing sizes */
15137cb013b1SChen-Yu Tsai static int ov5640_set_jpeg_timings(struct ov5640_dev *sensor,
15147cb013b1SChen-Yu Tsai 				   const struct ov5640_mode_info *mode)
15157cb013b1SChen-Yu Tsai {
15167cb013b1SChen-Yu Tsai 	int ret;
15177cb013b1SChen-Yu Tsai 
15182b5c18f9SChen-Yu Tsai 	/*
15192b5c18f9SChen-Yu Tsai 	 * compression mode 3 timing
15202b5c18f9SChen-Yu Tsai 	 *
15212b5c18f9SChen-Yu Tsai 	 * Data is transmitted with programmable width (VFIFO_HSIZE).
15222b5c18f9SChen-Yu Tsai 	 * No padding done. Last line may have less data. Varying
15232b5c18f9SChen-Yu Tsai 	 * number of lines per frame, depending on amount of data.
15242b5c18f9SChen-Yu Tsai 	 */
15252b5c18f9SChen-Yu Tsai 	ret = ov5640_mod_reg(sensor, OV5640_REG_JPG_MODE_SELECT, 0x7, 0x3);
15262b5c18f9SChen-Yu Tsai 	if (ret < 0)
15272b5c18f9SChen-Yu Tsai 		return ret;
15282b5c18f9SChen-Yu Tsai 
15295113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_VFIFO_HSIZE, mode->width);
15307cb013b1SChen-Yu Tsai 	if (ret < 0)
15317cb013b1SChen-Yu Tsai 		return ret;
15327cb013b1SChen-Yu Tsai 
15335113d5b3SJacopo Mondi 	return ov5640_write_reg16(sensor, OV5640_REG_VFIFO_VSIZE, mode->height);
15347cb013b1SChen-Yu Tsai }
15357cb013b1SChen-Yu Tsai 
153619a81c14SSteve Longerbeam /* download ov5640 settings to sensor through i2c */
1537bad1774eSJacopo Mondi static int ov5640_set_timings(struct ov5640_dev *sensor,
1538bad1774eSJacopo Mondi 			      const struct ov5640_mode_info *mode)
1539bad1774eSJacopo Mondi {
15405113d5b3SJacopo Mondi 	const struct ov5640_timings *timings;
15415113d5b3SJacopo Mondi 	const struct v4l2_rect *analog_crop;
15425113d5b3SJacopo Mondi 	const struct v4l2_rect *crop;
1543bad1774eSJacopo Mondi 	int ret;
1544bad1774eSJacopo Mondi 
15457cb013b1SChen-Yu Tsai 	if (sensor->fmt.code == MEDIA_BUS_FMT_JPEG_1X8) {
15467cb013b1SChen-Yu Tsai 		ret = ov5640_set_jpeg_timings(sensor, mode);
15477cb013b1SChen-Yu Tsai 		if (ret < 0)
15487cb013b1SChen-Yu Tsai 			return ret;
15497cb013b1SChen-Yu Tsai 	}
15507cb013b1SChen-Yu Tsai 
15512de6bb97SJacopo Mondi 	timings = ov5640_timings(sensor, mode);
15525113d5b3SJacopo Mondi 	analog_crop = &timings->analog_crop;
15535113d5b3SJacopo Mondi 	crop = &timings->crop;
15545113d5b3SJacopo Mondi 
15553145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HS,
15563145efcdSJacopo Mondi 				 analog_crop->left);
1557bad1774eSJacopo Mondi 	if (ret < 0)
1558bad1774eSJacopo Mondi 		return ret;
1559bad1774eSJacopo Mondi 
15603145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VS,
15613145efcdSJacopo Mondi 				 analog_crop->top);
15623145efcdSJacopo Mondi 	if (ret < 0)
15633145efcdSJacopo Mondi 		return ret;
15643145efcdSJacopo Mondi 
15653145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HW,
15663145efcdSJacopo Mondi 				 analog_crop->left + analog_crop->width - 1);
15673145efcdSJacopo Mondi 	if (ret < 0)
15683145efcdSJacopo Mondi 		return ret;
15693145efcdSJacopo Mondi 
15703145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VH,
15713145efcdSJacopo Mondi 				 analog_crop->top + analog_crop->height - 1);
15723145efcdSJacopo Mondi 	if (ret < 0)
15733145efcdSJacopo Mondi 		return ret;
15743145efcdSJacopo Mondi 
15753145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HOFFS, crop->left);
15763145efcdSJacopo Mondi 	if (ret < 0)
15773145efcdSJacopo Mondi 		return ret;
15783145efcdSJacopo Mondi 
15793145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VOFFS, crop->top);
15803145efcdSJacopo Mondi 	if (ret < 0)
15813145efcdSJacopo Mondi 		return ret;
15823145efcdSJacopo Mondi 
15835113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->width);
15843145efcdSJacopo Mondi 	if (ret < 0)
15853145efcdSJacopo Mondi 		return ret;
15863145efcdSJacopo Mondi 
15875113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, mode->height);
1588bad1774eSJacopo Mondi 	if (ret < 0)
1589bad1774eSJacopo Mondi 		return ret;
1590bad1774eSJacopo Mondi 
15915113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, timings->htot);
1592bad1774eSJacopo Mondi 	if (ret < 0)
1593bad1774eSJacopo Mondi 		return ret;
1594bad1774eSJacopo Mondi 
15953145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS,
15965113d5b3SJacopo Mondi 				 mode->height + timings->vblank_def);
15973145efcdSJacopo Mondi 	if (ret < 0)
15983145efcdSJacopo Mondi 		return ret;
15993145efcdSJacopo Mondi 
16003145efcdSJacopo Mondi 	return 0;
1601bad1774eSJacopo Mondi }
1602bad1774eSJacopo Mondi 
1603e4359019SJacopo Mondi static void ov5640_load_regs(struct ov5640_dev *sensor,
1604e4359019SJacopo Mondi 			     const struct reg_value *regs, unsigned int regnum)
160519a81c14SSteve Longerbeam {
160619a81c14SSteve Longerbeam 	unsigned int i;
160719a81c14SSteve Longerbeam 	u32 delay_ms;
160819a81c14SSteve Longerbeam 	u16 reg_addr;
160919a81c14SSteve Longerbeam 	u8 mask, val;
161019a81c14SSteve Longerbeam 	int ret = 0;
161119a81c14SSteve Longerbeam 
1612e4359019SJacopo Mondi 	for (i = 0; i < regnum; ++i, ++regs) {
161319a81c14SSteve Longerbeam 		delay_ms = regs->delay_ms;
161419a81c14SSteve Longerbeam 		reg_addr = regs->reg_addr;
161519a81c14SSteve Longerbeam 		val = regs->val;
161619a81c14SSteve Longerbeam 		mask = regs->mask;
161719a81c14SSteve Longerbeam 
16183b987d70SLad Prabhakar 		/* remain in power down mode for DVP */
16193b987d70SLad Prabhakar 		if (regs->reg_addr == OV5640_REG_SYS_CTRL0 &&
16203b987d70SLad Prabhakar 		    val == OV5640_REG_SYS_CTRL0_SW_PWUP &&
16218e823f5cSJacopo Mondi 		    !ov5640_is_csi2(sensor))
16223b987d70SLad Prabhakar 			continue;
16233b987d70SLad Prabhakar 
162419a81c14SSteve Longerbeam 		if (mask)
162519a81c14SSteve Longerbeam 			ret = ov5640_mod_reg(sensor, reg_addr, mask, val);
162619a81c14SSteve Longerbeam 		else
162719a81c14SSteve Longerbeam 			ret = ov5640_write_reg(sensor, reg_addr, val);
162819a81c14SSteve Longerbeam 		if (ret)
162919a81c14SSteve Longerbeam 			break;
163019a81c14SSteve Longerbeam 
163119a81c14SSteve Longerbeam 		if (delay_ms)
163219a81c14SSteve Longerbeam 			usleep_range(1000 * delay_ms, 1000 * delay_ms + 100);
163319a81c14SSteve Longerbeam 	}
163419a81c14SSteve Longerbeam }
163519a81c14SSteve Longerbeam 
1636dc29a1c1SHugues Fruchet static int ov5640_set_autoexposure(struct ov5640_dev *sensor, bool on)
1637dc29a1c1SHugues Fruchet {
1638dc29a1c1SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
1639dc29a1c1SHugues Fruchet 			      BIT(0), on ? 0 : BIT(0));
1640dc29a1c1SHugues Fruchet }
1641dc29a1c1SHugues Fruchet 
164219a81c14SSteve Longerbeam /* read exposure, in number of line periods */
164319a81c14SSteve Longerbeam static int ov5640_get_exposure(struct ov5640_dev *sensor)
164419a81c14SSteve Longerbeam {
164519a81c14SSteve Longerbeam 	int exp, ret;
164619a81c14SSteve Longerbeam 	u8 temp;
164719a81c14SSteve Longerbeam 
164819a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_HI, &temp);
164919a81c14SSteve Longerbeam 	if (ret)
165019a81c14SSteve Longerbeam 		return ret;
165119a81c14SSteve Longerbeam 	exp = ((int)temp & 0x0f) << 16;
165219a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_MED, &temp);
165319a81c14SSteve Longerbeam 	if (ret)
165419a81c14SSteve Longerbeam 		return ret;
165519a81c14SSteve Longerbeam 	exp |= ((int)temp << 8);
165619a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_LO, &temp);
165719a81c14SSteve Longerbeam 	if (ret)
165819a81c14SSteve Longerbeam 		return ret;
165919a81c14SSteve Longerbeam 	exp |= (int)temp;
166019a81c14SSteve Longerbeam 
166119a81c14SSteve Longerbeam 	return exp >> 4;
166219a81c14SSteve Longerbeam }
166319a81c14SSteve Longerbeam 
166419a81c14SSteve Longerbeam /* write exposure, given number of line periods */
166519a81c14SSteve Longerbeam static int ov5640_set_exposure(struct ov5640_dev *sensor, u32 exposure)
166619a81c14SSteve Longerbeam {
166719a81c14SSteve Longerbeam 	int ret;
166819a81c14SSteve Longerbeam 
166919a81c14SSteve Longerbeam 	exposure <<= 4;
167019a81c14SSteve Longerbeam 
167119a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor,
167219a81c14SSteve Longerbeam 			       OV5640_REG_AEC_PK_EXPOSURE_LO,
167319a81c14SSteve Longerbeam 			       exposure & 0xff);
167419a81c14SSteve Longerbeam 	if (ret)
167519a81c14SSteve Longerbeam 		return ret;
167619a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor,
167719a81c14SSteve Longerbeam 			       OV5640_REG_AEC_PK_EXPOSURE_MED,
167819a81c14SSteve Longerbeam 			       (exposure >> 8) & 0xff);
167919a81c14SSteve Longerbeam 	if (ret)
168019a81c14SSteve Longerbeam 		return ret;
168119a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor,
168219a81c14SSteve Longerbeam 				OV5640_REG_AEC_PK_EXPOSURE_HI,
168319a81c14SSteve Longerbeam 				(exposure >> 16) & 0x0f);
168419a81c14SSteve Longerbeam }
168519a81c14SSteve Longerbeam 
168619a81c14SSteve Longerbeam static int ov5640_get_gain(struct ov5640_dev *sensor)
168719a81c14SSteve Longerbeam {
168819a81c14SSteve Longerbeam 	u16 gain;
168919a81c14SSteve Longerbeam 	int ret;
169019a81c14SSteve Longerbeam 
169119a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN, &gain);
169219a81c14SSteve Longerbeam 	if (ret)
169319a81c14SSteve Longerbeam 		return ret;
169419a81c14SSteve Longerbeam 
169519a81c14SSteve Longerbeam 	return gain & 0x3ff;
169619a81c14SSteve Longerbeam }
169719a81c14SSteve Longerbeam 
16983cca8ef5SHugues Fruchet static int ov5640_set_gain(struct ov5640_dev *sensor, int gain)
16993cca8ef5SHugues Fruchet {
17003cca8ef5SHugues Fruchet 	return ov5640_write_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN,
17013cca8ef5SHugues Fruchet 				  (u16)gain & 0x3ff);
17023cca8ef5SHugues Fruchet }
17033cca8ef5SHugues Fruchet 
17043cca8ef5SHugues Fruchet static int ov5640_set_autogain(struct ov5640_dev *sensor, bool on)
17053cca8ef5SHugues Fruchet {
17063cca8ef5SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
17073cca8ef5SHugues Fruchet 			      BIT(1), on ? 0 : BIT(1));
17083cca8ef5SHugues Fruchet }
17093cca8ef5SHugues Fruchet 
1710f22996dbSHugues Fruchet static int ov5640_set_stream_dvp(struct ov5640_dev *sensor, bool on)
1711f22996dbSHugues Fruchet {
17123b987d70SLad Prabhakar 	return ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0, on ?
17133b987d70SLad Prabhakar 				OV5640_REG_SYS_CTRL0_SW_PWUP :
17143b987d70SLad Prabhakar 				OV5640_REG_SYS_CTRL0_SW_PWDN);
1715f22996dbSHugues Fruchet }
1716f22996dbSHugues Fruchet 
1717f22996dbSHugues Fruchet static int ov5640_set_stream_mipi(struct ov5640_dev *sensor, bool on)
171819a81c14SSteve Longerbeam {
171919a81c14SSteve Longerbeam 	int ret;
172019a81c14SSteve Longerbeam 
1721aa4bb8b8SJacopo Mondi 	/*
1722aa4bb8b8SJacopo Mondi 	 * Enable/disable the MIPI interface
1723aa4bb8b8SJacopo Mondi 	 *
1724aa4bb8b8SJacopo Mondi 	 * 0x300e = on ? 0x45 : 0x40
1725aa4bb8b8SJacopo Mondi 	 *
1726aa4bb8b8SJacopo Mondi 	 * FIXME: the sensor manual (version 2.03) reports
1727aa4bb8b8SJacopo Mondi 	 * [7:5] = 000  : 1 data lane mode
1728aa4bb8b8SJacopo Mondi 	 * [7:5] = 001  : 2 data lanes mode
1729aa4bb8b8SJacopo Mondi 	 * But this settings do not work, while the following ones
1730aa4bb8b8SJacopo Mondi 	 * have been validated for 2 data lanes mode.
1731aa4bb8b8SJacopo Mondi 	 *
1732aa4bb8b8SJacopo Mondi 	 * [7:5] = 010	: 2 data lanes mode
1733aa4bb8b8SJacopo Mondi 	 * [4] = 0	: Power up MIPI HS Tx
1734aa4bb8b8SJacopo Mondi 	 * [3] = 0	: Power up MIPI LS Rx
1735aa4bb8b8SJacopo Mondi 	 * [2] = 1/0	: MIPI interface enable/disable
1736aa4bb8b8SJacopo Mondi 	 * [1:0] = 01/00: FIXME: 'debug'
1737aa4bb8b8SJacopo Mondi 	 */
1738aa4bb8b8SJacopo Mondi 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00,
1739aa4bb8b8SJacopo Mondi 			       on ? 0x45 : 0x40);
174019a81c14SSteve Longerbeam 	if (ret)
174119a81c14SSteve Longerbeam 		return ret;
174219a81c14SSteve Longerbeam 
174319a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_FRAME_CTRL01,
174419a81c14SSteve Longerbeam 				on ? 0x00 : 0x0f);
174519a81c14SSteve Longerbeam }
174619a81c14SSteve Longerbeam 
174719a81c14SSteve Longerbeam static int ov5640_get_sysclk(struct ov5640_dev *sensor)
174819a81c14SSteve Longerbeam {
174919a81c14SSteve Longerbeam 	 /* calculate sysclk */
175019a81c14SSteve Longerbeam 	u32 xvclk = sensor->xclk_freq / 10000;
175119a81c14SSteve Longerbeam 	u32 multiplier, prediv, VCO, sysdiv, pll_rdiv;
175219a81c14SSteve Longerbeam 	u32 sclk_rdiv_map[] = {1, 2, 4, 8};
175319a81c14SSteve Longerbeam 	u32 bit_div2x = 1, sclk_rdiv, sysclk;
175419a81c14SSteve Longerbeam 	u8 temp1, temp2;
175519a81c14SSteve Longerbeam 	int ret;
175619a81c14SSteve Longerbeam 
175719a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL0, &temp1);
175819a81c14SSteve Longerbeam 	if (ret)
175919a81c14SSteve Longerbeam 		return ret;
176019a81c14SSteve Longerbeam 	temp2 = temp1 & 0x0f;
176119a81c14SSteve Longerbeam 	if (temp2 == 8 || temp2 == 10)
176219a81c14SSteve Longerbeam 		bit_div2x = temp2 / 2;
176319a81c14SSteve Longerbeam 
176419a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL1, &temp1);
176519a81c14SSteve Longerbeam 	if (ret)
176619a81c14SSteve Longerbeam 		return ret;
176719a81c14SSteve Longerbeam 	sysdiv = temp1 >> 4;
176819a81c14SSteve Longerbeam 	if (sysdiv == 0)
176919a81c14SSteve Longerbeam 		sysdiv = 16;
177019a81c14SSteve Longerbeam 
177119a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL2, &temp1);
177219a81c14SSteve Longerbeam 	if (ret)
177319a81c14SSteve Longerbeam 		return ret;
177419a81c14SSteve Longerbeam 	multiplier = temp1;
177519a81c14SSteve Longerbeam 
177619a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL3, &temp1);
177719a81c14SSteve Longerbeam 	if (ret)
177819a81c14SSteve Longerbeam 		return ret;
177919a81c14SSteve Longerbeam 	prediv = temp1 & 0x0f;
178019a81c14SSteve Longerbeam 	pll_rdiv = ((temp1 >> 4) & 0x01) + 1;
178119a81c14SSteve Longerbeam 
178219a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, &temp1);
178319a81c14SSteve Longerbeam 	if (ret)
178419a81c14SSteve Longerbeam 		return ret;
178519a81c14SSteve Longerbeam 	temp2 = temp1 & 0x03;
178619a81c14SSteve Longerbeam 	sclk_rdiv = sclk_rdiv_map[temp2];
178719a81c14SSteve Longerbeam 
178819a81c14SSteve Longerbeam 	if (!prediv || !sysdiv || !pll_rdiv || !bit_div2x)
178919a81c14SSteve Longerbeam 		return -EINVAL;
179019a81c14SSteve Longerbeam 
179119a81c14SSteve Longerbeam 	VCO = xvclk * multiplier / prediv;
179219a81c14SSteve Longerbeam 
179319a81c14SSteve Longerbeam 	sysclk = VCO / sysdiv / pll_rdiv * 2 / bit_div2x / sclk_rdiv;
179419a81c14SSteve Longerbeam 
179519a81c14SSteve Longerbeam 	return sysclk;
179619a81c14SSteve Longerbeam }
179719a81c14SSteve Longerbeam 
179819a81c14SSteve Longerbeam static int ov5640_set_night_mode(struct ov5640_dev *sensor)
179919a81c14SSteve Longerbeam {
180019a81c14SSteve Longerbeam 	 /* read HTS from register settings */
180119a81c14SSteve Longerbeam 	u8 mode;
180219a81c14SSteve Longerbeam 	int ret;
180319a81c14SSteve Longerbeam 
180419a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_CTRL00, &mode);
180519a81c14SSteve Longerbeam 	if (ret)
180619a81c14SSteve Longerbeam 		return ret;
180719a81c14SSteve Longerbeam 	mode &= 0xfb;
180819a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL00, mode);
180919a81c14SSteve Longerbeam }
181019a81c14SSteve Longerbeam 
181119a81c14SSteve Longerbeam static int ov5640_get_hts(struct ov5640_dev *sensor)
181219a81c14SSteve Longerbeam {
181319a81c14SSteve Longerbeam 	/* read HTS from register settings */
181419a81c14SSteve Longerbeam 	u16 hts;
181519a81c14SSteve Longerbeam 	int ret;
181619a81c14SSteve Longerbeam 
181719a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_HTS, &hts);
181819a81c14SSteve Longerbeam 	if (ret)
181919a81c14SSteve Longerbeam 		return ret;
182019a81c14SSteve Longerbeam 	return hts;
182119a81c14SSteve Longerbeam }
182219a81c14SSteve Longerbeam 
182319a81c14SSteve Longerbeam static int ov5640_get_vts(struct ov5640_dev *sensor)
182419a81c14SSteve Longerbeam {
182519a81c14SSteve Longerbeam 	u16 vts;
182619a81c14SSteve Longerbeam 	int ret;
182719a81c14SSteve Longerbeam 
182819a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_VTS, &vts);
182919a81c14SSteve Longerbeam 	if (ret)
183019a81c14SSteve Longerbeam 		return ret;
183119a81c14SSteve Longerbeam 	return vts;
183219a81c14SSteve Longerbeam }
183319a81c14SSteve Longerbeam 
183419a81c14SSteve Longerbeam static int ov5640_set_vts(struct ov5640_dev *sensor, int vts)
183519a81c14SSteve Longerbeam {
183619a81c14SSteve Longerbeam 	return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, vts);
183719a81c14SSteve Longerbeam }
183819a81c14SSteve Longerbeam 
183919a81c14SSteve Longerbeam static int ov5640_get_light_freq(struct ov5640_dev *sensor)
184019a81c14SSteve Longerbeam {
184119a81c14SSteve Longerbeam 	/* get banding filter value */
184219a81c14SSteve Longerbeam 	int ret, light_freq = 0;
184319a81c14SSteve Longerbeam 	u8 temp, temp1;
184419a81c14SSteve Longerbeam 
184519a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL01, &temp);
184619a81c14SSteve Longerbeam 	if (ret)
184719a81c14SSteve Longerbeam 		return ret;
184819a81c14SSteve Longerbeam 
184919a81c14SSteve Longerbeam 	if (temp & 0x80) {
185019a81c14SSteve Longerbeam 		/* manual */
185119a81c14SSteve Longerbeam 		ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL00,
185219a81c14SSteve Longerbeam 				      &temp1);
185319a81c14SSteve Longerbeam 		if (ret)
185419a81c14SSteve Longerbeam 			return ret;
185519a81c14SSteve Longerbeam 		if (temp1 & 0x04) {
185619a81c14SSteve Longerbeam 			/* 50Hz */
185719a81c14SSteve Longerbeam 			light_freq = 50;
185819a81c14SSteve Longerbeam 		} else {
185919a81c14SSteve Longerbeam 			/* 60Hz */
186019a81c14SSteve Longerbeam 			light_freq = 60;
186119a81c14SSteve Longerbeam 		}
186219a81c14SSteve Longerbeam 	} else {
186319a81c14SSteve Longerbeam 		/* auto */
186419a81c14SSteve Longerbeam 		ret = ov5640_read_reg(sensor, OV5640_REG_SIGMADELTA_CTRL0C,
186519a81c14SSteve Longerbeam 				      &temp1);
186619a81c14SSteve Longerbeam 		if (ret)
186719a81c14SSteve Longerbeam 			return ret;
186819a81c14SSteve Longerbeam 
186919a81c14SSteve Longerbeam 		if (temp1 & 0x01) {
187019a81c14SSteve Longerbeam 			/* 50Hz */
187119a81c14SSteve Longerbeam 			light_freq = 50;
187219a81c14SSteve Longerbeam 		} else {
187319a81c14SSteve Longerbeam 			/* 60Hz */
187419a81c14SSteve Longerbeam 		}
187519a81c14SSteve Longerbeam 	}
187619a81c14SSteve Longerbeam 
187719a81c14SSteve Longerbeam 	return light_freq;
187819a81c14SSteve Longerbeam }
187919a81c14SSteve Longerbeam 
188019a81c14SSteve Longerbeam static int ov5640_set_bandingfilter(struct ov5640_dev *sensor)
188119a81c14SSteve Longerbeam {
188219a81c14SSteve Longerbeam 	u32 band_step60, max_band60, band_step50, max_band50, prev_vts;
188319a81c14SSteve Longerbeam 	int ret;
188419a81c14SSteve Longerbeam 
188519a81c14SSteve Longerbeam 	/* read preview PCLK */
188619a81c14SSteve Longerbeam 	ret = ov5640_get_sysclk(sensor);
188719a81c14SSteve Longerbeam 	if (ret < 0)
188819a81c14SSteve Longerbeam 		return ret;
188919a81c14SSteve Longerbeam 	if (ret == 0)
189019a81c14SSteve Longerbeam 		return -EINVAL;
189119a81c14SSteve Longerbeam 	sensor->prev_sysclk = ret;
189219a81c14SSteve Longerbeam 	/* read preview HTS */
189319a81c14SSteve Longerbeam 	ret = ov5640_get_hts(sensor);
189419a81c14SSteve Longerbeam 	if (ret < 0)
189519a81c14SSteve Longerbeam 		return ret;
189619a81c14SSteve Longerbeam 	if (ret == 0)
189719a81c14SSteve Longerbeam 		return -EINVAL;
189819a81c14SSteve Longerbeam 	sensor->prev_hts = ret;
189919a81c14SSteve Longerbeam 
190019a81c14SSteve Longerbeam 	/* read preview VTS */
190119a81c14SSteve Longerbeam 	ret = ov5640_get_vts(sensor);
190219a81c14SSteve Longerbeam 	if (ret < 0)
190319a81c14SSteve Longerbeam 		return ret;
190419a81c14SSteve Longerbeam 	prev_vts = ret;
190519a81c14SSteve Longerbeam 
190619a81c14SSteve Longerbeam 	/* calculate banding filter */
190719a81c14SSteve Longerbeam 	/* 60Hz */
190819a81c14SSteve Longerbeam 	band_step60 = sensor->prev_sysclk * 100 / sensor->prev_hts * 100 / 120;
190919a81c14SSteve Longerbeam 	ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B60_STEP, band_step60);
191019a81c14SSteve Longerbeam 	if (ret)
191119a81c14SSteve Longerbeam 		return ret;
191219a81c14SSteve Longerbeam 	if (!band_step60)
191319a81c14SSteve Longerbeam 		return -EINVAL;
191419a81c14SSteve Longerbeam 	max_band60 = (int)((prev_vts - 4) / band_step60);
191519a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0D, max_band60);
191619a81c14SSteve Longerbeam 	if (ret)
191719a81c14SSteve Longerbeam 		return ret;
191819a81c14SSteve Longerbeam 
191919a81c14SSteve Longerbeam 	/* 50Hz */
192019a81c14SSteve Longerbeam 	band_step50 = sensor->prev_sysclk * 100 / sensor->prev_hts;
192119a81c14SSteve Longerbeam 	ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B50_STEP, band_step50);
192219a81c14SSteve Longerbeam 	if (ret)
192319a81c14SSteve Longerbeam 		return ret;
192419a81c14SSteve Longerbeam 	if (!band_step50)
192519a81c14SSteve Longerbeam 		return -EINVAL;
192619a81c14SSteve Longerbeam 	max_band50 = (int)((prev_vts - 4) / band_step50);
192719a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0E, max_band50);
192819a81c14SSteve Longerbeam }
192919a81c14SSteve Longerbeam 
193019a81c14SSteve Longerbeam static int ov5640_set_ae_target(struct ov5640_dev *sensor, int target)
193119a81c14SSteve Longerbeam {
193219a81c14SSteve Longerbeam 	/* stable in high */
193319a81c14SSteve Longerbeam 	u32 fast_high, fast_low;
193419a81c14SSteve Longerbeam 	int ret;
193519a81c14SSteve Longerbeam 
193619a81c14SSteve Longerbeam 	sensor->ae_low = target * 23 / 25;	/* 0.92 */
193719a81c14SSteve Longerbeam 	sensor->ae_high = target * 27 / 25;	/* 1.08 */
193819a81c14SSteve Longerbeam 
193919a81c14SSteve Longerbeam 	fast_high = sensor->ae_high << 1;
194019a81c14SSteve Longerbeam 	if (fast_high > 255)
194119a81c14SSteve Longerbeam 		fast_high = 255;
194219a81c14SSteve Longerbeam 
194319a81c14SSteve Longerbeam 	fast_low = sensor->ae_low >> 1;
194419a81c14SSteve Longerbeam 
194519a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0F, sensor->ae_high);
194619a81c14SSteve Longerbeam 	if (ret)
194719a81c14SSteve Longerbeam 		return ret;
194819a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL10, sensor->ae_low);
194919a81c14SSteve Longerbeam 	if (ret)
195019a81c14SSteve Longerbeam 		return ret;
195119a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1B, sensor->ae_high);
195219a81c14SSteve Longerbeam 	if (ret)
195319a81c14SSteve Longerbeam 		return ret;
195419a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1E, sensor->ae_low);
195519a81c14SSteve Longerbeam 	if (ret)
195619a81c14SSteve Longerbeam 		return ret;
195719a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL11, fast_high);
195819a81c14SSteve Longerbeam 	if (ret)
195919a81c14SSteve Longerbeam 		return ret;
196019a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1F, fast_low);
196119a81c14SSteve Longerbeam }
196219a81c14SSteve Longerbeam 
1963c2c3f42dSHugues Fruchet static int ov5640_get_binning(struct ov5640_dev *sensor)
196419a81c14SSteve Longerbeam {
196519a81c14SSteve Longerbeam 	u8 temp;
196619a81c14SSteve Longerbeam 	int ret;
196719a81c14SSteve Longerbeam 
196819a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_TIMING_TC_REG21, &temp);
196919a81c14SSteve Longerbeam 	if (ret)
197019a81c14SSteve Longerbeam 		return ret;
1971c2c3f42dSHugues Fruchet 
1972c2c3f42dSHugues Fruchet 	return temp & BIT(0);
197319a81c14SSteve Longerbeam }
197419a81c14SSteve Longerbeam 
1975ce85705aSHugues Fruchet static int ov5640_set_binning(struct ov5640_dev *sensor, bool enable)
1976ce85705aSHugues Fruchet {
1977ce85705aSHugues Fruchet 	int ret;
1978ce85705aSHugues Fruchet 
1979ce85705aSHugues Fruchet 	/*
1980ce85705aSHugues Fruchet 	 * TIMING TC REG21:
1981ce85705aSHugues Fruchet 	 * - [0]:	Horizontal binning enable
1982ce85705aSHugues Fruchet 	 */
1983ce85705aSHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
1984ce85705aSHugues Fruchet 			     BIT(0), enable ? BIT(0) : 0);
1985ce85705aSHugues Fruchet 	if (ret)
1986ce85705aSHugues Fruchet 		return ret;
1987ce85705aSHugues Fruchet 	/*
1988ce85705aSHugues Fruchet 	 * TIMING TC REG20:
1989ce85705aSHugues Fruchet 	 * - [0]:	Undocumented, but hardcoded init sequences
1990ce85705aSHugues Fruchet 	 *		are always setting REG21/REG20 bit 0 to same value...
1991ce85705aSHugues Fruchet 	 */
1992ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20,
1993ce85705aSHugues Fruchet 			      BIT(0), enable ? BIT(0) : 0);
1994ce85705aSHugues Fruchet }
1995ce85705aSHugues Fruchet 
199619a81c14SSteve Longerbeam static int ov5640_set_virtual_channel(struct ov5640_dev *sensor)
199719a81c14SSteve Longerbeam {
19988670d70aSHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
199919a81c14SSteve Longerbeam 	u8 temp, channel = virtual_channel;
200019a81c14SSteve Longerbeam 	int ret;
200119a81c14SSteve Longerbeam 
20028670d70aSHugues Fruchet 	if (channel > 3) {
20038670d70aSHugues Fruchet 		dev_err(&client->dev,
20048670d70aSHugues Fruchet 			"%s: wrong virtual_channel parameter, expected (0..3), got %d\n",
20058670d70aSHugues Fruchet 			__func__, channel);
200619a81c14SSteve Longerbeam 		return -EINVAL;
20078670d70aSHugues Fruchet 	}
200819a81c14SSteve Longerbeam 
200919a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_DEBUG_MODE, &temp);
201019a81c14SSteve Longerbeam 	if (ret)
201119a81c14SSteve Longerbeam 		return ret;
201219a81c14SSteve Longerbeam 	temp &= ~(3 << 6);
201319a81c14SSteve Longerbeam 	temp |= (channel << 6);
201419a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_DEBUG_MODE, temp);
201519a81c14SSteve Longerbeam }
201619a81c14SSteve Longerbeam 
201719a81c14SSteve Longerbeam static const struct ov5640_mode_info *
2018b6ae5022SJacopo Mondi ov5640_find_mode(struct ov5640_dev *sensor, int width, int height, bool nearest)
201919a81c14SSteve Longerbeam {
20203c4a7372SHugues Fruchet 	const struct ov5640_mode_info *mode;
202119a81c14SSteve Longerbeam 
2022086c25f8SMaxime Ripard 	mode = v4l2_find_nearest_size(ov5640_mode_data,
2023086c25f8SMaxime Ripard 				      ARRAY_SIZE(ov5640_mode_data),
20245113d5b3SJacopo Mondi 				      width, height, width, height);
202519a81c14SSteve Longerbeam 
20263c4a7372SHugues Fruchet 	if (!mode ||
20273145efcdSJacopo Mondi 	    (!nearest &&
20285113d5b3SJacopo Mondi 	     (mode->width != width || mode->height != height)))
20293c4a7372SHugues Fruchet 		return NULL;
203019a81c14SSteve Longerbeam 
203119a81c14SSteve Longerbeam 	return mode;
203219a81c14SSteve Longerbeam }
203319a81c14SSteve Longerbeam 
203419a81c14SSteve Longerbeam /*
203519a81c14SSteve Longerbeam  * sensor changes between scaling and subsampling, go through
203619a81c14SSteve Longerbeam  * exposure calculation
203719a81c14SSteve Longerbeam  */
203841d8d7f5SHugues Fruchet static int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor,
203941d8d7f5SHugues Fruchet 					 const struct ov5640_mode_info *mode)
204019a81c14SSteve Longerbeam {
204119a81c14SSteve Longerbeam 	u32 prev_shutter, prev_gain16;
204219a81c14SSteve Longerbeam 	u32 cap_shutter, cap_gain16;
204319a81c14SSteve Longerbeam 	u32 cap_sysclk, cap_hts, cap_vts;
204419a81c14SSteve Longerbeam 	u32 light_freq, cap_bandfilt, cap_maxband;
204519a81c14SSteve Longerbeam 	u32 cap_gain16_shutter;
204619a81c14SSteve Longerbeam 	u8 average;
204719a81c14SSteve Longerbeam 	int ret;
204819a81c14SSteve Longerbeam 
204941d8d7f5SHugues Fruchet 	if (!mode->reg_data)
205019a81c14SSteve Longerbeam 		return -EINVAL;
205119a81c14SSteve Longerbeam 
205219a81c14SSteve Longerbeam 	/* read preview shutter */
205319a81c14SSteve Longerbeam 	ret = ov5640_get_exposure(sensor);
205419a81c14SSteve Longerbeam 	if (ret < 0)
205519a81c14SSteve Longerbeam 		return ret;
205619a81c14SSteve Longerbeam 	prev_shutter = ret;
2057c2c3f42dSHugues Fruchet 	ret = ov5640_get_binning(sensor);
205819a81c14SSteve Longerbeam 	if (ret < 0)
205919a81c14SSteve Longerbeam 		return ret;
206019a81c14SSteve Longerbeam 	if (ret && mode->id != OV5640_MODE_720P_1280_720 &&
206119a81c14SSteve Longerbeam 	    mode->id != OV5640_MODE_1080P_1920_1080)
206219a81c14SSteve Longerbeam 		prev_shutter *= 2;
206319a81c14SSteve Longerbeam 
206419a81c14SSteve Longerbeam 	/* read preview gain */
206519a81c14SSteve Longerbeam 	ret = ov5640_get_gain(sensor);
206619a81c14SSteve Longerbeam 	if (ret < 0)
206719a81c14SSteve Longerbeam 		return ret;
206819a81c14SSteve Longerbeam 	prev_gain16 = ret;
206919a81c14SSteve Longerbeam 
207019a81c14SSteve Longerbeam 	/* get average */
207119a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AVG_READOUT, &average);
207219a81c14SSteve Longerbeam 	if (ret)
207319a81c14SSteve Longerbeam 		return ret;
207419a81c14SSteve Longerbeam 
207519a81c14SSteve Longerbeam 	/* turn off night mode for capture */
207619a81c14SSteve Longerbeam 	ret = ov5640_set_night_mode(sensor);
207719a81c14SSteve Longerbeam 	if (ret < 0)
207819a81c14SSteve Longerbeam 		return ret;
207919a81c14SSteve Longerbeam 
208019a81c14SSteve Longerbeam 	/* Write capture setting */
2081e4359019SJacopo Mondi 	ov5640_load_regs(sensor, mode->reg_data, mode->reg_data_size);
2082e4359019SJacopo Mondi 	ret = ov5640_set_timings(sensor, mode);
208319a81c14SSteve Longerbeam 	if (ret < 0)
208419a81c14SSteve Longerbeam 		return ret;
208519a81c14SSteve Longerbeam 
208619a81c14SSteve Longerbeam 	/* read capture VTS */
208719a81c14SSteve Longerbeam 	ret = ov5640_get_vts(sensor);
208819a81c14SSteve Longerbeam 	if (ret < 0)
208919a81c14SSteve Longerbeam 		return ret;
209019a81c14SSteve Longerbeam 	cap_vts = ret;
209119a81c14SSteve Longerbeam 	ret = ov5640_get_hts(sensor);
209219a81c14SSteve Longerbeam 	if (ret < 0)
209319a81c14SSteve Longerbeam 		return ret;
209419a81c14SSteve Longerbeam 	if (ret == 0)
209519a81c14SSteve Longerbeam 		return -EINVAL;
209619a81c14SSteve Longerbeam 	cap_hts = ret;
209719a81c14SSteve Longerbeam 
209819a81c14SSteve Longerbeam 	ret = ov5640_get_sysclk(sensor);
209919a81c14SSteve Longerbeam 	if (ret < 0)
210019a81c14SSteve Longerbeam 		return ret;
210119a81c14SSteve Longerbeam 	if (ret == 0)
210219a81c14SSteve Longerbeam 		return -EINVAL;
210319a81c14SSteve Longerbeam 	cap_sysclk = ret;
210419a81c14SSteve Longerbeam 
210519a81c14SSteve Longerbeam 	/* calculate capture banding filter */
210619a81c14SSteve Longerbeam 	ret = ov5640_get_light_freq(sensor);
210719a81c14SSteve Longerbeam 	if (ret < 0)
210819a81c14SSteve Longerbeam 		return ret;
210919a81c14SSteve Longerbeam 	light_freq = ret;
211019a81c14SSteve Longerbeam 
211119a81c14SSteve Longerbeam 	if (light_freq == 60) {
211219a81c14SSteve Longerbeam 		/* 60Hz */
211319a81c14SSteve Longerbeam 		cap_bandfilt = cap_sysclk * 100 / cap_hts * 100 / 120;
211419a81c14SSteve Longerbeam 	} else {
211519a81c14SSteve Longerbeam 		/* 50Hz */
211619a81c14SSteve Longerbeam 		cap_bandfilt = cap_sysclk * 100 / cap_hts;
211719a81c14SSteve Longerbeam 	}
211819a81c14SSteve Longerbeam 
211919a81c14SSteve Longerbeam 	if (!sensor->prev_sysclk) {
212019a81c14SSteve Longerbeam 		ret = ov5640_get_sysclk(sensor);
212119a81c14SSteve Longerbeam 		if (ret < 0)
212219a81c14SSteve Longerbeam 			return ret;
212319a81c14SSteve Longerbeam 		if (ret == 0)
212419a81c14SSteve Longerbeam 			return -EINVAL;
212519a81c14SSteve Longerbeam 		sensor->prev_sysclk = ret;
212619a81c14SSteve Longerbeam 	}
212719a81c14SSteve Longerbeam 
212819a81c14SSteve Longerbeam 	if (!cap_bandfilt)
212919a81c14SSteve Longerbeam 		return -EINVAL;
213019a81c14SSteve Longerbeam 
213119a81c14SSteve Longerbeam 	cap_maxband = (int)((cap_vts - 4) / cap_bandfilt);
213219a81c14SSteve Longerbeam 
213319a81c14SSteve Longerbeam 	/* calculate capture shutter/gain16 */
213419a81c14SSteve Longerbeam 	if (average > sensor->ae_low && average < sensor->ae_high) {
213519a81c14SSteve Longerbeam 		/* in stable range */
213619a81c14SSteve Longerbeam 		cap_gain16_shutter =
213719a81c14SSteve Longerbeam 			prev_gain16 * prev_shutter *
213819a81c14SSteve Longerbeam 			cap_sysclk / sensor->prev_sysclk *
213919a81c14SSteve Longerbeam 			sensor->prev_hts / cap_hts *
214019a81c14SSteve Longerbeam 			sensor->ae_target / average;
214119a81c14SSteve Longerbeam 	} else {
214219a81c14SSteve Longerbeam 		cap_gain16_shutter =
214319a81c14SSteve Longerbeam 			prev_gain16 * prev_shutter *
214419a81c14SSteve Longerbeam 			cap_sysclk / sensor->prev_sysclk *
214519a81c14SSteve Longerbeam 			sensor->prev_hts / cap_hts;
214619a81c14SSteve Longerbeam 	}
214719a81c14SSteve Longerbeam 
214819a81c14SSteve Longerbeam 	/* gain to shutter */
214919a81c14SSteve Longerbeam 	if (cap_gain16_shutter < (cap_bandfilt * 16)) {
215019a81c14SSteve Longerbeam 		/* shutter < 1/100 */
215119a81c14SSteve Longerbeam 		cap_shutter = cap_gain16_shutter / 16;
215219a81c14SSteve Longerbeam 		if (cap_shutter < 1)
215319a81c14SSteve Longerbeam 			cap_shutter = 1;
215419a81c14SSteve Longerbeam 
215519a81c14SSteve Longerbeam 		cap_gain16 = cap_gain16_shutter / cap_shutter;
215619a81c14SSteve Longerbeam 		if (cap_gain16 < 16)
215719a81c14SSteve Longerbeam 			cap_gain16 = 16;
215819a81c14SSteve Longerbeam 	} else {
215919a81c14SSteve Longerbeam 		if (cap_gain16_shutter > (cap_bandfilt * cap_maxband * 16)) {
216019a81c14SSteve Longerbeam 			/* exposure reach max */
216119a81c14SSteve Longerbeam 			cap_shutter = cap_bandfilt * cap_maxband;
216219a81c14SSteve Longerbeam 			if (!cap_shutter)
216319a81c14SSteve Longerbeam 				return -EINVAL;
216419a81c14SSteve Longerbeam 
216519a81c14SSteve Longerbeam 			cap_gain16 = cap_gain16_shutter / cap_shutter;
216619a81c14SSteve Longerbeam 		} else {
216719a81c14SSteve Longerbeam 			/* 1/100 < (cap_shutter = n/100) =< max */
216819a81c14SSteve Longerbeam 			cap_shutter =
216919a81c14SSteve Longerbeam 				((int)(cap_gain16_shutter / 16 / cap_bandfilt))
217019a81c14SSteve Longerbeam 				* cap_bandfilt;
217119a81c14SSteve Longerbeam 			if (!cap_shutter)
217219a81c14SSteve Longerbeam 				return -EINVAL;
217319a81c14SSteve Longerbeam 
217419a81c14SSteve Longerbeam 			cap_gain16 = cap_gain16_shutter / cap_shutter;
217519a81c14SSteve Longerbeam 		}
217619a81c14SSteve Longerbeam 	}
217719a81c14SSteve Longerbeam 
217819a81c14SSteve Longerbeam 	/* set capture gain */
21793cca8ef5SHugues Fruchet 	ret = ov5640_set_gain(sensor, cap_gain16);
218019a81c14SSteve Longerbeam 	if (ret)
218119a81c14SSteve Longerbeam 		return ret;
218219a81c14SSteve Longerbeam 
218319a81c14SSteve Longerbeam 	/* write capture shutter */
218419a81c14SSteve Longerbeam 	if (cap_shutter > (cap_vts - 4)) {
218519a81c14SSteve Longerbeam 		cap_vts = cap_shutter + 4;
218619a81c14SSteve Longerbeam 		ret = ov5640_set_vts(sensor, cap_vts);
218719a81c14SSteve Longerbeam 		if (ret < 0)
218819a81c14SSteve Longerbeam 			return ret;
218919a81c14SSteve Longerbeam 	}
219019a81c14SSteve Longerbeam 
219119a81c14SSteve Longerbeam 	/* set exposure */
21923cca8ef5SHugues Fruchet 	return ov5640_set_exposure(sensor, cap_shutter);
219319a81c14SSteve Longerbeam }
219419a81c14SSteve Longerbeam 
219519a81c14SSteve Longerbeam /*
219619a81c14SSteve Longerbeam  * if sensor changes inside scaling or subsampling
219719a81c14SSteve Longerbeam  * change mode directly
219819a81c14SSteve Longerbeam  */
219919a81c14SSteve Longerbeam static int ov5640_set_mode_direct(struct ov5640_dev *sensor,
22003cca8ef5SHugues Fruchet 				  const struct ov5640_mode_info *mode)
220119a81c14SSteve Longerbeam {
220241d8d7f5SHugues Fruchet 	if (!mode->reg_data)
220319a81c14SSteve Longerbeam 		return -EINVAL;
220419a81c14SSteve Longerbeam 
220519a81c14SSteve Longerbeam 	/* Write capture setting */
2206e4359019SJacopo Mondi 	ov5640_load_regs(sensor, mode->reg_data, mode->reg_data_size);
2207e4359019SJacopo Mondi 	return ov5640_set_timings(sensor, mode);
220819a81c14SSteve Longerbeam }
220919a81c14SSteve Longerbeam 
2210985cdcb0SHugues Fruchet static int ov5640_set_mode(struct ov5640_dev *sensor)
221119a81c14SSteve Longerbeam {
221219a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode = sensor->current_mode;
2213985cdcb0SHugues Fruchet 	const struct ov5640_mode_info *orig_mode = sensor->last_mode;
221419a81c14SSteve Longerbeam 	enum ov5640_downsize_mode dn_mode, orig_dn_mode;
22153cca8ef5SHugues Fruchet 	bool auto_gain = sensor->ctrls.auto_gain->val == 1;
2216dc29a1c1SHugues Fruchet 	bool auto_exp =  sensor->ctrls.auto_exp->val == V4L2_EXPOSURE_AUTO;
221719a81c14SSteve Longerbeam 	int ret;
221819a81c14SSteve Longerbeam 
221919a81c14SSteve Longerbeam 	dn_mode = mode->dn_mode;
222019a81c14SSteve Longerbeam 	orig_dn_mode = orig_mode->dn_mode;
222119a81c14SSteve Longerbeam 
222219a81c14SSteve Longerbeam 	/* auto gain and exposure must be turned off when changing modes */
22233cca8ef5SHugues Fruchet 	if (auto_gain) {
22243cca8ef5SHugues Fruchet 		ret = ov5640_set_autogain(sensor, false);
222519a81c14SSteve Longerbeam 		if (ret)
222619a81c14SSteve Longerbeam 			return ret;
22273cca8ef5SHugues Fruchet 	}
2228bf4a4b51SMaxime Ripard 
22293cca8ef5SHugues Fruchet 	if (auto_exp) {
2230dc29a1c1SHugues Fruchet 		ret = ov5640_set_autoexposure(sensor, false);
223119a81c14SSteve Longerbeam 		if (ret)
22323cca8ef5SHugues Fruchet 			goto restore_auto_gain;
22333cca8ef5SHugues Fruchet 	}
223419a81c14SSteve Longerbeam 
22356c957ed7SJacopo Mondi 	if (ov5640_is_csi2(sensor))
22366c957ed7SJacopo Mondi 		ret = ov5640_set_mipi_pclk(sensor);
22376c957ed7SJacopo Mondi 	else
22386c957ed7SJacopo Mondi 		ret = ov5640_set_dvp_pclk(sensor);
2239aa288248SMaxime Ripard 	if (ret < 0)
2240aa288248SMaxime Ripard 		return 0;
2241aa288248SMaxime Ripard 
224219a81c14SSteve Longerbeam 	if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) ||
224319a81c14SSteve Longerbeam 	    (dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) {
224419a81c14SSteve Longerbeam 		/*
224519a81c14SSteve Longerbeam 		 * change between subsampling and scaling
22463cca8ef5SHugues Fruchet 		 * go through exposure calculation
224719a81c14SSteve Longerbeam 		 */
224819a81c14SSteve Longerbeam 		ret = ov5640_set_mode_exposure_calc(sensor, mode);
224919a81c14SSteve Longerbeam 	} else {
225019a81c14SSteve Longerbeam 		/*
225119a81c14SSteve Longerbeam 		 * change inside subsampling or scaling
225219a81c14SSteve Longerbeam 		 * download firmware directly
225319a81c14SSteve Longerbeam 		 */
22543cca8ef5SHugues Fruchet 		ret = ov5640_set_mode_direct(sensor, mode);
225519a81c14SSteve Longerbeam 	}
225619a81c14SSteve Longerbeam 	if (ret < 0)
22573cca8ef5SHugues Fruchet 		goto restore_auto_exp_gain;
22583cca8ef5SHugues Fruchet 
22593cca8ef5SHugues Fruchet 	/* restore auto gain and exposure */
22603cca8ef5SHugues Fruchet 	if (auto_gain)
22613cca8ef5SHugues Fruchet 		ov5640_set_autogain(sensor, true);
22623cca8ef5SHugues Fruchet 	if (auto_exp)
22633cca8ef5SHugues Fruchet 		ov5640_set_autoexposure(sensor, true);
226419a81c14SSteve Longerbeam 
2265ce85705aSHugues Fruchet 	ret = ov5640_set_binning(sensor, dn_mode != SCALING);
2266ce85705aSHugues Fruchet 	if (ret < 0)
2267ce85705aSHugues Fruchet 		return ret;
226819a81c14SSteve Longerbeam 	ret = ov5640_set_ae_target(sensor, sensor->ae_target);
226919a81c14SSteve Longerbeam 	if (ret < 0)
227019a81c14SSteve Longerbeam 		return ret;
227119a81c14SSteve Longerbeam 	ret = ov5640_get_light_freq(sensor);
227219a81c14SSteve Longerbeam 	if (ret < 0)
227319a81c14SSteve Longerbeam 		return ret;
227419a81c14SSteve Longerbeam 	ret = ov5640_set_bandingfilter(sensor);
227519a81c14SSteve Longerbeam 	if (ret < 0)
227619a81c14SSteve Longerbeam 		return ret;
227719a81c14SSteve Longerbeam 	ret = ov5640_set_virtual_channel(sensor);
227819a81c14SSteve Longerbeam 	if (ret < 0)
227919a81c14SSteve Longerbeam 		return ret;
228019a81c14SSteve Longerbeam 
228119a81c14SSteve Longerbeam 	sensor->pending_mode_change = false;
2282985cdcb0SHugues Fruchet 	sensor->last_mode = mode;
228319a81c14SSteve Longerbeam 
228419a81c14SSteve Longerbeam 	return 0;
22853cca8ef5SHugues Fruchet 
22863cca8ef5SHugues Fruchet restore_auto_exp_gain:
22873cca8ef5SHugues Fruchet 	if (auto_exp)
22883cca8ef5SHugues Fruchet 		ov5640_set_autoexposure(sensor, true);
22893cca8ef5SHugues Fruchet restore_auto_gain:
22903cca8ef5SHugues Fruchet 	if (auto_gain)
22913cca8ef5SHugues Fruchet 		ov5640_set_autogain(sensor, true);
22923cca8ef5SHugues Fruchet 
22933cca8ef5SHugues Fruchet 	return ret;
229419a81c14SSteve Longerbeam }
229519a81c14SSteve Longerbeam 
229619ad26f9SAkinobu Mita static int ov5640_set_framefmt(struct ov5640_dev *sensor,
229719ad26f9SAkinobu Mita 			       struct v4l2_mbus_framefmt *format);
229819ad26f9SAkinobu Mita 
229919a81c14SSteve Longerbeam /* restore the last set video mode after chip power-on */
230019a81c14SSteve Longerbeam static int ov5640_restore_mode(struct ov5640_dev *sensor)
230119a81c14SSteve Longerbeam {
230219a81c14SSteve Longerbeam 	int ret;
230319a81c14SSteve Longerbeam 
230419a81c14SSteve Longerbeam 	/* first load the initial register values */
2305e4359019SJacopo Mondi 	ov5640_load_regs(sensor, ov5640_init_setting,
2306e4359019SJacopo Mondi 			 ARRAY_SIZE(ov5640_init_setting));
230719a81c14SSteve Longerbeam 
23088f57c2f8SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
23097851fe7aSMaxime Ripard 			     (ilog2(OV5640_SCLK2X_ROOT_DIV) << 2) |
23107851fe7aSMaxime Ripard 			     ilog2(OV5640_SCLK_ROOT_DIV));
23118f57c2f8SMaxime Ripard 	if (ret)
23128f57c2f8SMaxime Ripard 		return ret;
23138f57c2f8SMaxime Ripard 
231419a81c14SSteve Longerbeam 	/* now restore the last capture mode */
2315985cdcb0SHugues Fruchet 	ret = ov5640_set_mode(sensor);
231619ad26f9SAkinobu Mita 	if (ret < 0)
231719ad26f9SAkinobu Mita 		return ret;
231819ad26f9SAkinobu Mita 
231919ad26f9SAkinobu Mita 	return ov5640_set_framefmt(sensor, &sensor->fmt);
232019a81c14SSteve Longerbeam }
232119a81c14SSteve Longerbeam 
232219a81c14SSteve Longerbeam static void ov5640_power(struct ov5640_dev *sensor, bool enable)
232319a81c14SSteve Longerbeam {
23241fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->pwdn_gpio, enable ? 0 : 1);
232519a81c14SSteve Longerbeam }
232619a81c14SSteve Longerbeam 
232719a81c14SSteve Longerbeam static void ov5640_reset(struct ov5640_dev *sensor)
232819a81c14SSteve Longerbeam {
232919a81c14SSteve Longerbeam 	if (!sensor->reset_gpio)
233019a81c14SSteve Longerbeam 		return;
233119a81c14SSteve Longerbeam 
23321fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 0);
233319a81c14SSteve Longerbeam 
233419a81c14SSteve Longerbeam 	/* camera power cycle */
233519a81c14SSteve Longerbeam 	ov5640_power(sensor, false);
233619a81c14SSteve Longerbeam 	usleep_range(5000, 10000);
233719a81c14SSteve Longerbeam 	ov5640_power(sensor, true);
233819a81c14SSteve Longerbeam 	usleep_range(5000, 10000);
233919a81c14SSteve Longerbeam 
23401fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 1);
234119a81c14SSteve Longerbeam 	usleep_range(1000, 2000);
234219a81c14SSteve Longerbeam 
23431fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 0);
23441d4c41f3SLoic Poulain 	usleep_range(20000, 25000);
234519a81c14SSteve Longerbeam }
234619a81c14SSteve Longerbeam 
23470f7acb52SHugues Fruchet static int ov5640_set_power_on(struct ov5640_dev *sensor)
234819a81c14SSteve Longerbeam {
23490f7acb52SHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
23500f7acb52SHugues Fruchet 	int ret;
235119a81c14SSteve Longerbeam 
23520f7acb52SHugues Fruchet 	ret = clk_prepare_enable(sensor->xclk);
23530f7acb52SHugues Fruchet 	if (ret) {
23540f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to enable clock\n",
23550f7acb52SHugues Fruchet 			__func__);
23560f7acb52SHugues Fruchet 		return ret;
23570f7acb52SHugues Fruchet 	}
235819a81c14SSteve Longerbeam 
235919a81c14SSteve Longerbeam 	ret = regulator_bulk_enable(OV5640_NUM_SUPPLIES,
236019a81c14SSteve Longerbeam 				    sensor->supplies);
23610f7acb52SHugues Fruchet 	if (ret) {
23620f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to enable regulators\n",
23630f7acb52SHugues Fruchet 			__func__);
236419a81c14SSteve Longerbeam 		goto xclk_off;
23650f7acb52SHugues Fruchet 	}
236619a81c14SSteve Longerbeam 
236719a81c14SSteve Longerbeam 	ov5640_reset(sensor);
236819a81c14SSteve Longerbeam 	ov5640_power(sensor, true);
236919a81c14SSteve Longerbeam 
237019a81c14SSteve Longerbeam 	ret = ov5640_init_slave_id(sensor);
237119a81c14SSteve Longerbeam 	if (ret)
237219a81c14SSteve Longerbeam 		goto power_off;
237319a81c14SSteve Longerbeam 
23740f7acb52SHugues Fruchet 	return 0;
23750f7acb52SHugues Fruchet 
23760f7acb52SHugues Fruchet power_off:
23770f7acb52SHugues Fruchet 	ov5640_power(sensor, false);
23780f7acb52SHugues Fruchet 	regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies);
23790f7acb52SHugues Fruchet xclk_off:
23800f7acb52SHugues Fruchet 	clk_disable_unprepare(sensor->xclk);
23810f7acb52SHugues Fruchet 	return ret;
23820f7acb52SHugues Fruchet }
23830f7acb52SHugues Fruchet 
23840f7acb52SHugues Fruchet static void ov5640_set_power_off(struct ov5640_dev *sensor)
23850f7acb52SHugues Fruchet {
23860f7acb52SHugues Fruchet 	ov5640_power(sensor, false);
23870f7acb52SHugues Fruchet 	regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies);
23880f7acb52SHugues Fruchet 	clk_disable_unprepare(sensor->xclk);
23890f7acb52SHugues Fruchet }
23900f7acb52SHugues Fruchet 
2391b1751ae6SLad Prabhakar static int ov5640_set_power_mipi(struct ov5640_dev *sensor, bool on)
2392b1751ae6SLad Prabhakar {
2393b1751ae6SLad Prabhakar 	int ret;
2394b1751ae6SLad Prabhakar 
2395b1751ae6SLad Prabhakar 	if (!on) {
2396b1751ae6SLad Prabhakar 		/* Reset MIPI bus settings to their default values. */
2397b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
2398b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x04);
2399b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x00);
2400b1751ae6SLad Prabhakar 		return 0;
2401b1751ae6SLad Prabhakar 	}
2402b1751ae6SLad Prabhakar 
2403b1751ae6SLad Prabhakar 	/*
2404b1751ae6SLad Prabhakar 	 * Power up MIPI HS Tx and LS Rx; 2 data lanes mode
2405b1751ae6SLad Prabhakar 	 *
2406b1751ae6SLad Prabhakar 	 * 0x300e = 0x40
2407b1751ae6SLad Prabhakar 	 * [7:5] = 010	: 2 data lanes mode (see FIXME note in
2408b1751ae6SLad Prabhakar 	 *		  "ov5640_set_stream_mipi()")
2409b1751ae6SLad Prabhakar 	 * [4] = 0	: Power up MIPI HS Tx
2410b1751ae6SLad Prabhakar 	 * [3] = 0	: Power up MIPI LS Rx
2411b1751ae6SLad Prabhakar 	 * [2] = 0	: MIPI interface disabled
2412b1751ae6SLad Prabhakar 	 */
2413b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x40);
2414b1751ae6SLad Prabhakar 	if (ret)
2415b1751ae6SLad Prabhakar 		return ret;
2416b1751ae6SLad Prabhakar 
2417b1751ae6SLad Prabhakar 	/*
2418b1751ae6SLad Prabhakar 	 * Gate clock and set LP11 in 'no packets mode' (idle)
2419b1751ae6SLad Prabhakar 	 *
2420b1751ae6SLad Prabhakar 	 * 0x4800 = 0x24
2421b1751ae6SLad Prabhakar 	 * [5] = 1	: Gate clock when 'no packets'
2422b1751ae6SLad Prabhakar 	 * [2] = 1	: MIPI bus in LP11 when 'no packets'
2423b1751ae6SLad Prabhakar 	 */
2424b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x24);
2425b1751ae6SLad Prabhakar 	if (ret)
2426b1751ae6SLad Prabhakar 		return ret;
2427b1751ae6SLad Prabhakar 
2428b1751ae6SLad Prabhakar 	/*
2429b1751ae6SLad Prabhakar 	 * Set data lanes and clock in LP11 when 'sleeping'
2430b1751ae6SLad Prabhakar 	 *
2431b1751ae6SLad Prabhakar 	 * 0x3019 = 0x70
2432b1751ae6SLad Prabhakar 	 * [6] = 1	: MIPI data lane 2 in LP11 when 'sleeping'
2433b1751ae6SLad Prabhakar 	 * [5] = 1	: MIPI data lane 1 in LP11 when 'sleeping'
2434b1751ae6SLad Prabhakar 	 * [4] = 1	: MIPI clock lane in LP11 when 'sleeping'
2435b1751ae6SLad Prabhakar 	 */
2436b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x70);
2437b1751ae6SLad Prabhakar 	if (ret)
2438b1751ae6SLad Prabhakar 		return ret;
2439b1751ae6SLad Prabhakar 
2440b1751ae6SLad Prabhakar 	/* Give lanes some time to coax into LP11 state. */
2441b1751ae6SLad Prabhakar 	usleep_range(500, 1000);
2442b1751ae6SLad Prabhakar 
2443b1751ae6SLad Prabhakar 	return 0;
2444b1751ae6SLad Prabhakar }
2445b1751ae6SLad Prabhakar 
2446576f5d4bSLad Prabhakar static int ov5640_set_power_dvp(struct ov5640_dev *sensor, bool on)
2447576f5d4bSLad Prabhakar {
2448311a6408SLad Prabhakar 	unsigned int flags = sensor->ep.bus.parallel.flags;
244968579b32SHugues Fruchet 	bool bt656 = sensor->ep.bus_type == V4L2_MBUS_BT656;
245068579b32SHugues Fruchet 	u8 polarities = 0;
2451576f5d4bSLad Prabhakar 	int ret;
2452576f5d4bSLad Prabhakar 
2453576f5d4bSLad Prabhakar 	if (!on) {
2454576f5d4bSLad Prabhakar 		/* Reset settings to their default values. */
245568579b32SHugues Fruchet 		ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00, 0x00);
2456311a6408SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
2457311a6408SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, 0x20);
2458576f5d4bSLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01, 0x00);
2459576f5d4bSLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0x00);
2460576f5d4bSLad Prabhakar 		return 0;
2461576f5d4bSLad Prabhakar 	}
2462576f5d4bSLad Prabhakar 
2463576f5d4bSLad Prabhakar 	/*
2464311a6408SLad Prabhakar 	 * Note about parallel port configuration.
2465311a6408SLad Prabhakar 	 *
2466311a6408SLad Prabhakar 	 * When configured in parallel mode, the OV5640 will
2467311a6408SLad Prabhakar 	 * output 10 bits data on DVP data lines [9:0].
2468311a6408SLad Prabhakar 	 * If only 8 bits data are wanted, the 8 bits data lines
2469311a6408SLad Prabhakar 	 * of the camera interface must be physically connected
2470311a6408SLad Prabhakar 	 * on the DVP data lines [9:2].
2471311a6408SLad Prabhakar 	 *
2472311a6408SLad Prabhakar 	 * Control lines polarity can be configured through
2473311a6408SLad Prabhakar 	 * devicetree endpoint control lines properties.
2474311a6408SLad Prabhakar 	 * If no endpoint control lines properties are set,
2475311a6408SLad Prabhakar 	 * polarity will be as below:
2476311a6408SLad Prabhakar 	 * - VSYNC:	active high
2477311a6408SLad Prabhakar 	 * - HREF:	active low
2478311a6408SLad Prabhakar 	 * - PCLK:	active low
247968579b32SHugues Fruchet 	 *
248068579b32SHugues Fruchet 	 * VSYNC & HREF are not configured if BT656 bus mode is selected
2481311a6408SLad Prabhakar 	 */
248268579b32SHugues Fruchet 
248368579b32SHugues Fruchet 	/*
248468579b32SHugues Fruchet 	 * BT656 embedded synchronization configuration
248568579b32SHugues Fruchet 	 *
248668579b32SHugues Fruchet 	 * CCIR656 CTRL00
248768579b32SHugues Fruchet 	 * - [7]:	SYNC code selection (0: auto generate sync code,
248868579b32SHugues Fruchet 	 *		1: sync code from regs 0x4732-0x4735)
248968579b32SHugues Fruchet 	 * - [6]:	f value in CCIR656 SYNC code when fixed f value
249068579b32SHugues Fruchet 	 * - [5]:	Fixed f value
249168579b32SHugues Fruchet 	 * - [4:3]:	Blank toggle data options (00: data=1'h040/1'h200,
249268579b32SHugues Fruchet 	 *		01: data from regs 0x4736-0x4738, 10: always keep 0)
249368579b32SHugues Fruchet 	 * - [1]:	Clip data disable
249468579b32SHugues Fruchet 	 * - [0]:	CCIR656 mode enable
249568579b32SHugues Fruchet 	 *
249668579b32SHugues Fruchet 	 * Default CCIR656 SAV/EAV mode with default codes
249768579b32SHugues Fruchet 	 * SAV=0xff000080 & EAV=0xff00009d is enabled here with settings:
249868579b32SHugues Fruchet 	 * - CCIR656 mode enable
249968579b32SHugues Fruchet 	 * - auto generation of sync codes
250068579b32SHugues Fruchet 	 * - blank toggle data 1'h040/1'h200
250168579b32SHugues Fruchet 	 * - clip reserved data (0x00 & 0xff changed to 0x01 & 0xfe)
250268579b32SHugues Fruchet 	 */
250368579b32SHugues Fruchet 	ret = ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00,
250468579b32SHugues Fruchet 			       bt656 ? 0x01 : 0x00);
250568579b32SHugues Fruchet 	if (ret)
250668579b32SHugues Fruchet 		return ret;
250768579b32SHugues Fruchet 
2508311a6408SLad Prabhakar 	/*
2509311a6408SLad Prabhakar 	 * configure parallel port control lines polarity
2510311a6408SLad Prabhakar 	 *
2511311a6408SLad Prabhakar 	 * POLARITY CTRL0
2512311a6408SLad Prabhakar 	 * - [5]:	PCLK polarity (0: active low, 1: active high)
2513311a6408SLad Prabhakar 	 * - [1]:	HREF polarity (0: active low, 1: active high)
2514311a6408SLad Prabhakar 	 * - [0]:	VSYNC polarity (mismatch here between
2515311a6408SLad Prabhakar 	 *		datasheet and hardware, 0 is active high
2516311a6408SLad Prabhakar 	 *		and 1 is active low...)
2517311a6408SLad Prabhakar 	 */
251868579b32SHugues Fruchet 	if (!bt656) {
2519311a6408SLad Prabhakar 		if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
252068579b32SHugues Fruchet 			polarities |= BIT(1);
2521311a6408SLad Prabhakar 		if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
252268579b32SHugues Fruchet 			polarities |= BIT(0);
252368579b32SHugues Fruchet 	}
252468579b32SHugues Fruchet 	if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
252568579b32SHugues Fruchet 		polarities |= BIT(5);
2526311a6408SLad Prabhakar 
252768579b32SHugues Fruchet 	ret = ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, polarities);
2528311a6408SLad Prabhakar 	if (ret)
2529311a6408SLad Prabhakar 		return ret;
2530311a6408SLad Prabhakar 
2531311a6408SLad Prabhakar 	/*
253268579b32SHugues Fruchet 	 * powerdown MIPI TX/RX PHY & enable DVP
2533311a6408SLad Prabhakar 	 *
2534311a6408SLad Prabhakar 	 * MIPI CONTROL 00
253568579b32SHugues Fruchet 	 * [4] = 1	: Power down MIPI HS Tx
253668579b32SHugues Fruchet 	 * [3] = 1	: Power down MIPI LS Rx
253768579b32SHugues Fruchet 	 * [2] = 0	: DVP enable (MIPI disable)
2538311a6408SLad Prabhakar 	 */
2539311a6408SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x18);
2540311a6408SLad Prabhakar 	if (ret)
2541311a6408SLad Prabhakar 		return ret;
2542311a6408SLad Prabhakar 
2543311a6408SLad Prabhakar 	/*
2544576f5d4bSLad Prabhakar 	 * enable VSYNC/HREF/PCLK DVP control lines
2545576f5d4bSLad Prabhakar 	 * & D[9:6] DVP data lines
2546576f5d4bSLad Prabhakar 	 *
2547576f5d4bSLad Prabhakar 	 * PAD OUTPUT ENABLE 01
2548576f5d4bSLad Prabhakar 	 * - 6:		VSYNC output enable
2549576f5d4bSLad Prabhakar 	 * - 5:		HREF output enable
2550576f5d4bSLad Prabhakar 	 * - 4:		PCLK output enable
2551576f5d4bSLad Prabhakar 	 * - [3:0]:	D[9:6] output enable
2552576f5d4bSLad Prabhakar 	 */
25534039b037SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01,
255468579b32SHugues Fruchet 			       bt656 ? 0x1f : 0x7f);
2555576f5d4bSLad Prabhakar 	if (ret)
2556576f5d4bSLad Prabhakar 		return ret;
2557576f5d4bSLad Prabhakar 
2558576f5d4bSLad Prabhakar 	/*
2559576f5d4bSLad Prabhakar 	 * enable D[5:0] DVP data lines
2560576f5d4bSLad Prabhakar 	 *
2561576f5d4bSLad Prabhakar 	 * PAD OUTPUT ENABLE 02
2562576f5d4bSLad Prabhakar 	 * - [7:2]:	D[5:0] output enable
2563576f5d4bSLad Prabhakar 	 */
2564576f5d4bSLad Prabhakar 	return ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0xfc);
2565576f5d4bSLad Prabhakar }
2566576f5d4bSLad Prabhakar 
25670f7acb52SHugues Fruchet static int ov5640_set_power(struct ov5640_dev *sensor, bool on)
25680f7acb52SHugues Fruchet {
25690f7acb52SHugues Fruchet 	int ret = 0;
25700f7acb52SHugues Fruchet 
25710f7acb52SHugues Fruchet 	if (on) {
25720f7acb52SHugues Fruchet 		ret = ov5640_set_power_on(sensor);
25730f7acb52SHugues Fruchet 		if (ret)
25740f7acb52SHugues Fruchet 			return ret;
25750f7acb52SHugues Fruchet 
257619a81c14SSteve Longerbeam 		ret = ov5640_restore_mode(sensor);
257719a81c14SSteve Longerbeam 		if (ret)
257819a81c14SSteve Longerbeam 			goto power_off;
2579b1751ae6SLad Prabhakar 	}
258019a81c14SSteve Longerbeam 
2581576f5d4bSLad Prabhakar 	if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY)
2582b1751ae6SLad Prabhakar 		ret = ov5640_set_power_mipi(sensor, on);
2583576f5d4bSLad Prabhakar 	else
2584576f5d4bSLad Prabhakar 		ret = ov5640_set_power_dvp(sensor, on);
2585b1751ae6SLad Prabhakar 	if (ret)
2586b1751ae6SLad Prabhakar 		goto power_off;
2587aa4bb8b8SJacopo Mondi 
2588b1751ae6SLad Prabhakar 	if (!on)
2589aa4bb8b8SJacopo Mondi 		ov5640_set_power_off(sensor);
259019a81c14SSteve Longerbeam 
259119a81c14SSteve Longerbeam 	return 0;
259219a81c14SSteve Longerbeam 
259319a81c14SSteve Longerbeam power_off:
25940f7acb52SHugues Fruchet 	ov5640_set_power_off(sensor);
259519a81c14SSteve Longerbeam 	return ret;
259619a81c14SSteve Longerbeam }
259719a81c14SSteve Longerbeam 
259819a81c14SSteve Longerbeam /* --------------- Subdev Operations --------------- */
259919a81c14SSteve Longerbeam 
260019a81c14SSteve Longerbeam static int ov5640_s_power(struct v4l2_subdev *sd, int on)
260119a81c14SSteve Longerbeam {
260219a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
260319a81c14SSteve Longerbeam 	int ret = 0;
260419a81c14SSteve Longerbeam 
260519a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
260619a81c14SSteve Longerbeam 
260719a81c14SSteve Longerbeam 	/*
260819a81c14SSteve Longerbeam 	 * If the power count is modified from 0 to != 0 or from != 0 to 0,
260919a81c14SSteve Longerbeam 	 * update the power state.
261019a81c14SSteve Longerbeam 	 */
261119a81c14SSteve Longerbeam 	if (sensor->power_count == !on) {
261219a81c14SSteve Longerbeam 		ret = ov5640_set_power(sensor, !!on);
261319a81c14SSteve Longerbeam 		if (ret)
261419a81c14SSteve Longerbeam 			goto out;
261519a81c14SSteve Longerbeam 	}
261619a81c14SSteve Longerbeam 
261719a81c14SSteve Longerbeam 	/* Update the power count. */
261819a81c14SSteve Longerbeam 	sensor->power_count += on ? 1 : -1;
261919a81c14SSteve Longerbeam 	WARN_ON(sensor->power_count < 0);
262019a81c14SSteve Longerbeam out:
262119a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
262219a81c14SSteve Longerbeam 
262319a81c14SSteve Longerbeam 	if (on && !ret && sensor->power_count == 1) {
262419a81c14SSteve Longerbeam 		/* restore controls */
262519a81c14SSteve Longerbeam 		ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
262619a81c14SSteve Longerbeam 	}
262719a81c14SSteve Longerbeam 
262819a81c14SSteve Longerbeam 	return ret;
262919a81c14SSteve Longerbeam }
263019a81c14SSteve Longerbeam 
263119a81c14SSteve Longerbeam static int ov5640_try_frame_interval(struct ov5640_dev *sensor,
263219a81c14SSteve Longerbeam 				     struct v4l2_fract *fi,
263319a81c14SSteve Longerbeam 				     u32 width, u32 height)
263419a81c14SSteve Longerbeam {
263519a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
26366530a5ebSJagan Teki 	enum ov5640_frame_rate rate = OV5640_15_FPS;
2637f6cc192fSMaxime Ripard 	int minfps, maxfps, best_fps, fps;
2638f6cc192fSMaxime Ripard 	int i;
263919a81c14SSteve Longerbeam 
264019a81c14SSteve Longerbeam 	minfps = ov5640_framerates[OV5640_15_FPS];
2641e823fb16SMaxime Ripard 	maxfps = ov5640_framerates[OV5640_60_FPS];
264219a81c14SSteve Longerbeam 
264319a81c14SSteve Longerbeam 	if (fi->numerator == 0) {
264419a81c14SSteve Longerbeam 		fi->denominator = maxfps;
264519a81c14SSteve Longerbeam 		fi->numerator = 1;
2646e823fb16SMaxime Ripard 		rate = OV5640_60_FPS;
2647e823fb16SMaxime Ripard 		goto find_mode;
264819a81c14SSteve Longerbeam 	}
264919a81c14SSteve Longerbeam 
2650f6cc192fSMaxime Ripard 	fps = clamp_val(DIV_ROUND_CLOSEST(fi->denominator, fi->numerator),
2651f6cc192fSMaxime Ripard 			minfps, maxfps);
2652f6cc192fSMaxime Ripard 
2653f6cc192fSMaxime Ripard 	best_fps = minfps;
2654f6cc192fSMaxime Ripard 	for (i = 0; i < ARRAY_SIZE(ov5640_framerates); i++) {
2655f6cc192fSMaxime Ripard 		int curr_fps = ov5640_framerates[i];
2656f6cc192fSMaxime Ripard 
2657f6cc192fSMaxime Ripard 		if (abs(curr_fps - fps) < abs(best_fps - fps)) {
2658f6cc192fSMaxime Ripard 			best_fps = curr_fps;
2659f6cc192fSMaxime Ripard 			rate = i;
2660f6cc192fSMaxime Ripard 		}
2661f6cc192fSMaxime Ripard 	}
266219a81c14SSteve Longerbeam 
266319a81c14SSteve Longerbeam 	fi->numerator = 1;
2664f6cc192fSMaxime Ripard 	fi->denominator = best_fps;
266519a81c14SSteve Longerbeam 
2666e823fb16SMaxime Ripard find_mode:
2667b6ae5022SJacopo Mondi 	mode = ov5640_find_mode(sensor, width, height, false);
26685a3ad937SMaxime Ripard 	return mode ? rate : -EINVAL;
266919a81c14SSteve Longerbeam }
267019a81c14SSteve Longerbeam 
267119a81c14SSteve Longerbeam static int ov5640_get_fmt(struct v4l2_subdev *sd,
26720d346d2aSTomi Valkeinen 			  struct v4l2_subdev_state *sd_state,
267319a81c14SSteve Longerbeam 			  struct v4l2_subdev_format *format)
267419a81c14SSteve Longerbeam {
267519a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
267619a81c14SSteve Longerbeam 	struct v4l2_mbus_framefmt *fmt;
267719a81c14SSteve Longerbeam 
267819a81c14SSteve Longerbeam 	if (format->pad != 0)
267919a81c14SSteve Longerbeam 		return -EINVAL;
268019a81c14SSteve Longerbeam 
268119a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
268219a81c14SSteve Longerbeam 
268319a81c14SSteve Longerbeam 	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
26840d346d2aSTomi Valkeinen 		fmt = v4l2_subdev_get_try_format(&sensor->sd, sd_state,
268519a81c14SSteve Longerbeam 						 format->pad);
268619a81c14SSteve Longerbeam 	else
268719a81c14SSteve Longerbeam 		fmt = &sensor->fmt;
268819a81c14SSteve Longerbeam 
268919a81c14SSteve Longerbeam 	format->format = *fmt;
269019a81c14SSteve Longerbeam 
269119a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
269219a81c14SSteve Longerbeam 
269319a81c14SSteve Longerbeam 	return 0;
269419a81c14SSteve Longerbeam }
269519a81c14SSteve Longerbeam 
269619a81c14SSteve Longerbeam static int ov5640_try_fmt_internal(struct v4l2_subdev *sd,
269719a81c14SSteve Longerbeam 				   struct v4l2_mbus_framefmt *fmt,
269819a81c14SSteve Longerbeam 				   enum ov5640_frame_rate fr,
269919a81c14SSteve Longerbeam 				   const struct ov5640_mode_info **new_mode)
270019a81c14SSteve Longerbeam {
2701*dd81b8ffSJacopo Mondi 	unsigned int bpp = ov5640_code_to_bpp(fmt->code);
270219a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
270319a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
2704e3ee691dSHugues Fruchet 	int i;
270519a81c14SSteve Longerbeam 
2706b6ae5022SJacopo Mondi 	mode = ov5640_find_mode(sensor, fmt->width, fmt->height, true);
270719a81c14SSteve Longerbeam 	if (!mode)
270819a81c14SSteve Longerbeam 		return -EINVAL;
2709*dd81b8ffSJacopo Mondi 
2710*dd81b8ffSJacopo Mondi 	/*
2711*dd81b8ffSJacopo Mondi 	 * Adjust mode according to bpp:
2712*dd81b8ffSJacopo Mondi 	 * - 8bpp modes work for resolution >= 1280x720
2713*dd81b8ffSJacopo Mondi 	 * - 24bpp modes work resolution < 1280x720
2714*dd81b8ffSJacopo Mondi 	 */
2715*dd81b8ffSJacopo Mondi 	if (bpp == 8 && mode->width < 1280)
2716*dd81b8ffSJacopo Mondi 		mode = &ov5640_mode_data[OV5640_MODE_720P_1280_720];
2717*dd81b8ffSJacopo Mondi 	else if (bpp == 24 && mode->width > 1024)
2718*dd81b8ffSJacopo Mondi 		mode = &ov5640_mode_data[OV5640_MODE_XGA_1024_768];
2719*dd81b8ffSJacopo Mondi 
27205113d5b3SJacopo Mondi 	fmt->width = mode->width;
27215113d5b3SJacopo Mondi 	fmt->height = mode->height;
272219a81c14SSteve Longerbeam 
272319a81c14SSteve Longerbeam 	if (new_mode)
272419a81c14SSteve Longerbeam 		*new_mode = mode;
2725e3ee691dSHugues Fruchet 
2726e3ee691dSHugues Fruchet 	for (i = 0; i < ARRAY_SIZE(ov5640_formats); i++)
2727e3ee691dSHugues Fruchet 		if (ov5640_formats[i].code == fmt->code)
2728e3ee691dSHugues Fruchet 			break;
2729e3ee691dSHugues Fruchet 	if (i >= ARRAY_SIZE(ov5640_formats))
2730e6441fdeSHugues Fruchet 		i = 0;
2731e6441fdeSHugues Fruchet 
2732e6441fdeSHugues Fruchet 	fmt->code = ov5640_formats[i].code;
2733e6441fdeSHugues Fruchet 	fmt->colorspace = ov5640_formats[i].colorspace;
2734e6441fdeSHugues Fruchet 	fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
2735e6441fdeSHugues Fruchet 	fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
2736e6441fdeSHugues Fruchet 	fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
2737e3ee691dSHugues Fruchet 
273819a81c14SSteve Longerbeam 	return 0;
273919a81c14SSteve Longerbeam }
274019a81c14SSteve Longerbeam 
27413c28588fSJacopo Mondi static int ov5640_update_pixel_rate(struct ov5640_dev *sensor)
27423c28588fSJacopo Mondi {
27433c28588fSJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
27443c28588fSJacopo Mondi 	enum ov5640_pixel_rate_id pixel_rate_id = mode->pixel_rate;
27453c28588fSJacopo Mondi 	struct v4l2_mbus_framefmt *fmt = &sensor->fmt;
274632979f67SJacopo Mondi 	const struct ov5640_timings *timings;
2747bce93b82SJacopo Mondi 	s32 exposure_val, exposure_max;
274832979f67SJacopo Mondi 	unsigned int hblank;
27493c28588fSJacopo Mondi 	unsigned int i = 0;
27503c28588fSJacopo Mondi 	u32 pixel_rate;
27513c28588fSJacopo Mondi 	s64 link_freq;
27523c28588fSJacopo Mondi 	u32 num_lanes;
275319f2e3e6SHugues Fruchet 	u32 vblank;
27543c28588fSJacopo Mondi 	u32 bpp;
27553c28588fSJacopo Mondi 
27563c28588fSJacopo Mondi 	/*
27573c28588fSJacopo Mondi 	 * Update the pixel rate control value.
27583c28588fSJacopo Mondi 	 *
27593c28588fSJacopo Mondi 	 * For DVP mode, maintain the pixel rate calculation using fixed FPS.
27603c28588fSJacopo Mondi 	 */
27613c28588fSJacopo Mondi 	if (!ov5640_is_csi2(sensor)) {
27623c28588fSJacopo Mondi 		__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate,
27633c28588fSJacopo Mondi 					 ov5640_calc_pixel_rate(sensor));
27643c28588fSJacopo Mondi 
27653c28588fSJacopo Mondi 		return 0;
27663c28588fSJacopo Mondi 	}
27673c28588fSJacopo Mondi 
27683c28588fSJacopo Mondi 	/*
27693c28588fSJacopo Mondi 	 * The MIPI CSI-2 link frequency should comply with the CSI-2
27703c28588fSJacopo Mondi 	 * specification and be lower than 1GHz.
27713c28588fSJacopo Mondi 	 *
27723c28588fSJacopo Mondi 	 * Start from the suggested pixel_rate for the current mode and
27733c28588fSJacopo Mondi 	 * progressively slow it down if it exceeds 1GHz.
27743c28588fSJacopo Mondi 	 */
27753c28588fSJacopo Mondi 	num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes;
27763c28588fSJacopo Mondi 	bpp = ov5640_code_to_bpp(fmt->code);
27773c28588fSJacopo Mondi 	do {
27783c28588fSJacopo Mondi 		pixel_rate = ov5640_pixel_rates[pixel_rate_id];
27793c28588fSJacopo Mondi 		link_freq = pixel_rate * bpp / (2 * num_lanes);
27803c28588fSJacopo Mondi 	} while (link_freq >= 1000000000U &&
27813c28588fSJacopo Mondi 		 ++pixel_rate_id < OV5640_NUM_PIXEL_RATES);
27823c28588fSJacopo Mondi 
27833c28588fSJacopo Mondi 	sensor->current_link_freq = link_freq;
27843c28588fSJacopo Mondi 
27853c28588fSJacopo Mondi 	/*
27863c28588fSJacopo Mondi 	 * Higher link rates require the clock tree to be programmed with
27873c28588fSJacopo Mondi 	 * 'mipi_div' = 1; this has the effect of halving the actual output
27883c28588fSJacopo Mondi 	 * pixel rate in the MIPI domain.
27893c28588fSJacopo Mondi 	 *
27903c28588fSJacopo Mondi 	 * Adjust the pixel rate and link frequency control value to report it
27913c28588fSJacopo Mondi 	 * correctly to userspace.
27923c28588fSJacopo Mondi 	 */
27933c28588fSJacopo Mondi 	if (link_freq > OV5640_LINK_RATE_MAX) {
27943c28588fSJacopo Mondi 		pixel_rate /= 2;
27953c28588fSJacopo Mondi 		link_freq /= 2;
27963c28588fSJacopo Mondi 	}
27973c28588fSJacopo Mondi 
27983c28588fSJacopo Mondi 	for (i = 0; i < ARRAY_SIZE(ov5640_csi2_link_freqs); ++i) {
27993c28588fSJacopo Mondi 		if (ov5640_csi2_link_freqs[i] == link_freq)
28003c28588fSJacopo Mondi 			break;
28013c28588fSJacopo Mondi 	}
28023c28588fSJacopo Mondi 	WARN_ON(i == ARRAY_SIZE(ov5640_csi2_link_freqs));
28033c28588fSJacopo Mondi 
28043c28588fSJacopo Mondi 	__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, pixel_rate);
28053c28588fSJacopo Mondi 	__v4l2_ctrl_s_ctrl(sensor->ctrls.link_freq, i);
28063c28588fSJacopo Mondi 
280732979f67SJacopo Mondi 	timings = ov5640_timings(sensor, mode);
280832979f67SJacopo Mondi 	hblank = timings->htot - mode->width;
280932979f67SJacopo Mondi 	__v4l2_ctrl_modify_range(sensor->ctrls.hblank,
281032979f67SJacopo Mondi 				 hblank, hblank, 1, hblank);
281132979f67SJacopo Mondi 
281219f2e3e6SHugues Fruchet 	vblank = timings->vblank_def;
2813bce93b82SJacopo Mondi 
281419f2e3e6SHugues Fruchet 	if (sensor->current_fr != mode->def_fps) {
281519f2e3e6SHugues Fruchet 		/*
281619f2e3e6SHugues Fruchet 		 * Compute the vertical blanking according to the framerate
281719f2e3e6SHugues Fruchet 		 * configured with s_frame_interval.
281819f2e3e6SHugues Fruchet 		 */
281919f2e3e6SHugues Fruchet 		int fie_num = sensor->frame_interval.numerator;
282019f2e3e6SHugues Fruchet 		int fie_denom = sensor->frame_interval.denominator;
282119f2e3e6SHugues Fruchet 
282219f2e3e6SHugues Fruchet 		vblank = ((fie_num * pixel_rate / fie_denom) / timings->htot) -
282319f2e3e6SHugues Fruchet 			mode->height;
282419f2e3e6SHugues Fruchet 	}
282519f2e3e6SHugues Fruchet 
282619f2e3e6SHugues Fruchet 	__v4l2_ctrl_modify_range(sensor->ctrls.vblank, OV5640_MIN_VBLANK,
282719f2e3e6SHugues Fruchet 				 OV5640_MAX_VTS - mode->height, 1, vblank);
282819f2e3e6SHugues Fruchet 	__v4l2_ctrl_s_ctrl(sensor->ctrls.vblank, vblank);
282919f2e3e6SHugues Fruchet 
283019f2e3e6SHugues Fruchet 	exposure_max = timings->crop.height + vblank - 4;
2831bce93b82SJacopo Mondi 	exposure_val = clamp_t(s32, sensor->ctrls.exposure->val,
2832bce93b82SJacopo Mondi 			       sensor->ctrls.exposure->minimum,
2833bce93b82SJacopo Mondi 			       exposure_max);
283419f2e3e6SHugues Fruchet 
2835bce93b82SJacopo Mondi 	__v4l2_ctrl_modify_range(sensor->ctrls.exposure,
2836bce93b82SJacopo Mondi 				 sensor->ctrls.exposure->minimum,
2837bce93b82SJacopo Mondi 				 exposure_max, 1, exposure_val);
2838bce93b82SJacopo Mondi 
28393c28588fSJacopo Mondi 	return 0;
28403c28588fSJacopo Mondi }
28413c28588fSJacopo Mondi 
284219a81c14SSteve Longerbeam static int ov5640_set_fmt(struct v4l2_subdev *sd,
28430d346d2aSTomi Valkeinen 			  struct v4l2_subdev_state *sd_state,
284419a81c14SSteve Longerbeam 			  struct v4l2_subdev_format *format)
284519a81c14SSteve Longerbeam {
284619a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
284719a81c14SSteve Longerbeam 	const struct ov5640_mode_info *new_mode;
2848e6441fdeSHugues Fruchet 	struct v4l2_mbus_framefmt *mbus_fmt = &format->format;
284919a81c14SSteve Longerbeam 	int ret;
285019a81c14SSteve Longerbeam 
285119a81c14SSteve Longerbeam 	if (format->pad != 0)
285219a81c14SSteve Longerbeam 		return -EINVAL;
285319a81c14SSteve Longerbeam 
285419a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
285519a81c14SSteve Longerbeam 
285619a81c14SSteve Longerbeam 	if (sensor->streaming) {
285719a81c14SSteve Longerbeam 		ret = -EBUSY;
285819a81c14SSteve Longerbeam 		goto out;
285919a81c14SSteve Longerbeam 	}
286019a81c14SSteve Longerbeam 
2861e6441fdeSHugues Fruchet 	ret = ov5640_try_fmt_internal(sd, mbus_fmt,
286219a81c14SSteve Longerbeam 				      sensor->current_fr, &new_mode);
286319a81c14SSteve Longerbeam 	if (ret)
286419a81c14SSteve Longerbeam 		goto out;
286519a81c14SSteve Longerbeam 
2866e738f5ddSMirela Rabulea 	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
2867e738f5ddSMirela Rabulea 		*v4l2_subdev_get_try_format(sd, sd_state, 0) = *mbus_fmt;
2868e738f5ddSMirela Rabulea 		goto out;
2869e738f5ddSMirela Rabulea 	}
287019a81c14SSteve Longerbeam 
28716949d864SHugues Fruchet 	if (new_mode != sensor->current_mode) {
287219f2e3e6SHugues Fruchet 		sensor->current_fr = new_mode->def_fps;
287319a81c14SSteve Longerbeam 		sensor->current_mode = new_mode;
287419a81c14SSteve Longerbeam 		sensor->pending_mode_change = true;
28756949d864SHugues Fruchet 	}
287607115449SJacopo Mondi 	if (mbus_fmt->code != sensor->fmt.code)
2877fb98e29fSHugues Fruchet 		sensor->pending_fmt_change = true;
287807115449SJacopo Mondi 
2879e738f5ddSMirela Rabulea 	/* update format even if code is unchanged, resolution might change */
2880e738f5ddSMirela Rabulea 	sensor->fmt = *mbus_fmt;
2881e738f5ddSMirela Rabulea 
28823c28588fSJacopo Mondi 	ov5640_update_pixel_rate(sensor);
28833c28588fSJacopo Mondi 
288419a81c14SSteve Longerbeam out:
288519a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
288619a81c14SSteve Longerbeam 	return ret;
288719a81c14SSteve Longerbeam }
288819a81c14SSteve Longerbeam 
288966ed85ebSJacopo Mondi static int ov5640_get_selection(struct v4l2_subdev *sd,
289066ed85ebSJacopo Mondi 				struct v4l2_subdev_state *sd_state,
289166ed85ebSJacopo Mondi 				struct v4l2_subdev_selection *sel)
289266ed85ebSJacopo Mondi {
289366ed85ebSJacopo Mondi 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
289466ed85ebSJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
289566ed85ebSJacopo Mondi 	const struct ov5640_timings *timings;
289666ed85ebSJacopo Mondi 
289766ed85ebSJacopo Mondi 	switch (sel->target) {
289866ed85ebSJacopo Mondi 	case V4L2_SEL_TGT_CROP: {
289966ed85ebSJacopo Mondi 		mutex_lock(&sensor->lock);
290066ed85ebSJacopo Mondi 		timings = ov5640_timings(sensor, mode);
290166ed85ebSJacopo Mondi 		sel->r = timings->analog_crop;
290266ed85ebSJacopo Mondi 		mutex_unlock(&sensor->lock);
290366ed85ebSJacopo Mondi 
290466ed85ebSJacopo Mondi 		return 0;
290566ed85ebSJacopo Mondi 	}
290666ed85ebSJacopo Mondi 
290766ed85ebSJacopo Mondi 	case V4L2_SEL_TGT_NATIVE_SIZE:
290866ed85ebSJacopo Mondi 	case V4L2_SEL_TGT_CROP_BOUNDS:
290966ed85ebSJacopo Mondi 		sel->r.top = 0;
291066ed85ebSJacopo Mondi 		sel->r.left = 0;
291166ed85ebSJacopo Mondi 		sel->r.width = OV5640_NATIVE_WIDTH;
291266ed85ebSJacopo Mondi 		sel->r.height = OV5640_NATIVE_HEIGHT;
291366ed85ebSJacopo Mondi 
291466ed85ebSJacopo Mondi 		return 0;
291566ed85ebSJacopo Mondi 
291666ed85ebSJacopo Mondi 	case V4L2_SEL_TGT_CROP_DEFAULT:
291766ed85ebSJacopo Mondi 		sel->r.top = OV5640_PIXEL_ARRAY_TOP;
291866ed85ebSJacopo Mondi 		sel->r.left = OV5640_PIXEL_ARRAY_LEFT;
291966ed85ebSJacopo Mondi 		sel->r.width = OV5640_PIXEL_ARRAY_WIDTH;
292066ed85ebSJacopo Mondi 		sel->r.height = OV5640_PIXEL_ARRAY_HEIGHT;
292166ed85ebSJacopo Mondi 
292266ed85ebSJacopo Mondi 		return 0;
292366ed85ebSJacopo Mondi 	}
292466ed85ebSJacopo Mondi 
292566ed85ebSJacopo Mondi 	return -EINVAL;
292666ed85ebSJacopo Mondi }
292766ed85ebSJacopo Mondi 
2928e3ee691dSHugues Fruchet static int ov5640_set_framefmt(struct ov5640_dev *sensor,
2929e3ee691dSHugues Fruchet 			       struct v4l2_mbus_framefmt *format)
2930e3ee691dSHugues Fruchet {
2931e3ee691dSHugues Fruchet 	int ret = 0;
2932d47c4126SHugues Fruchet 	bool is_jpeg = false;
2933b7ed3abdSLoic Poulain 	u8 fmt, mux;
2934e3ee691dSHugues Fruchet 
2935e3ee691dSHugues Fruchet 	switch (format->code) {
29361536fbdbSXavier Roumegue 	case MEDIA_BUS_FMT_UYVY8_1X16:
2937e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_UYVY8_2X8:
2938e3ee691dSHugues Fruchet 		/* YUV422, UYVY */
2939b7ed3abdSLoic Poulain 		fmt = 0x3f;
2940b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_YUV422;
2941e3ee691dSHugues Fruchet 		break;
29421536fbdbSXavier Roumegue 	case MEDIA_BUS_FMT_YUYV8_1X16:
2943e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_YUYV8_2X8:
2944e3ee691dSHugues Fruchet 		/* YUV422, YUYV */
2945b7ed3abdSLoic Poulain 		fmt = 0x30;
2946b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_YUV422;
2947e3ee691dSHugues Fruchet 		break;
2948e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_RGB565_2X8_LE:
29490a43fcd7SJacopo Mondi 	case MEDIA_BUS_FMT_RGB565_1X16:
2950e3ee691dSHugues Fruchet 		/* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */
2951b7ed3abdSLoic Poulain 		fmt = 0x6F;
2952b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RGB;
2953e3ee691dSHugues Fruchet 		break;
2954e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_RGB565_2X8_BE:
2955e3ee691dSHugues Fruchet 		/* RGB565 {r[4:0],g[5:3]},{g[2:0],b[4:0]} */
2956b7ed3abdSLoic Poulain 		fmt = 0x61;
2957b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RGB;
2958e3ee691dSHugues Fruchet 		break;
29596ac98b41SJacopo Mondi 	case MEDIA_BUS_FMT_BGR888_1X24:
29606ac98b41SJacopo Mondi 		/* BGR888: RGB */
29616ac98b41SJacopo Mondi 		fmt = 0x23;
29626ac98b41SJacopo Mondi 		mux = OV5640_FMT_MUX_RGB;
29636ac98b41SJacopo Mondi 		break;
2964d47c4126SHugues Fruchet 	case MEDIA_BUS_FMT_JPEG_1X8:
2965d47c4126SHugues Fruchet 		/* YUV422, YUYV */
2966b7ed3abdSLoic Poulain 		fmt = 0x30;
2967b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_YUV422;
2968d47c4126SHugues Fruchet 		is_jpeg = true;
2969d47c4126SHugues Fruchet 		break;
2970b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SBGGR8_1X8:
2971b7ed3abdSLoic Poulain 		/* Raw, BGBG... / GRGR... */
2972b7ed3abdSLoic Poulain 		fmt = 0x00;
2973b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2974b7ed3abdSLoic Poulain 		break;
2975b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SGBRG8_1X8:
2976b7ed3abdSLoic Poulain 		/* Raw bayer, GBGB... / RGRG... */
2977b7ed3abdSLoic Poulain 		fmt = 0x01;
2978b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2979b7ed3abdSLoic Poulain 		break;
2980b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SGRBG8_1X8:
2981b7ed3abdSLoic Poulain 		/* Raw bayer, GRGR... / BGBG... */
2982b7ed3abdSLoic Poulain 		fmt = 0x02;
2983b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2984b7ed3abdSLoic Poulain 		break;
2985b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SRGGB8_1X8:
2986b7ed3abdSLoic Poulain 		/* Raw bayer, RGRG... / GBGB... */
2987b7ed3abdSLoic Poulain 		fmt = 0x03;
2988b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2989b7ed3abdSLoic Poulain 		break;
2990e3ee691dSHugues Fruchet 	default:
2991e3ee691dSHugues Fruchet 		return -EINVAL;
2992e3ee691dSHugues Fruchet 	}
2993e3ee691dSHugues Fruchet 
2994e3ee691dSHugues Fruchet 	/* FORMAT CONTROL00: YUV and RGB formatting */
2995b7ed3abdSLoic Poulain 	ret = ov5640_write_reg(sensor, OV5640_REG_FORMAT_CONTROL00, fmt);
2996e3ee691dSHugues Fruchet 	if (ret)
2997e3ee691dSHugues Fruchet 		return ret;
2998e3ee691dSHugues Fruchet 
2999e3ee691dSHugues Fruchet 	/* FORMAT MUX CONTROL: ISP YUV or RGB */
3000b7ed3abdSLoic Poulain 	ret = ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL, mux);
3001d47c4126SHugues Fruchet 	if (ret)
3002d47c4126SHugues Fruchet 		return ret;
3003d47c4126SHugues Fruchet 
3004d47c4126SHugues Fruchet 	/*
3005d47c4126SHugues Fruchet 	 * TIMING TC REG21:
3006d47c4126SHugues Fruchet 	 * - [5]:	JPEG enable
3007d47c4126SHugues Fruchet 	 */
3008d47c4126SHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
3009d47c4126SHugues Fruchet 			     BIT(5), is_jpeg ? BIT(5) : 0);
3010d47c4126SHugues Fruchet 	if (ret)
3011d47c4126SHugues Fruchet 		return ret;
3012d47c4126SHugues Fruchet 
3013d47c4126SHugues Fruchet 	/*
3014d47c4126SHugues Fruchet 	 * SYSTEM RESET02:
3015d47c4126SHugues Fruchet 	 * - [4]:	Reset JFIFO
3016d47c4126SHugues Fruchet 	 * - [3]:	Reset SFIFO
3017d47c4126SHugues Fruchet 	 * - [2]:	Reset JPEG
3018d47c4126SHugues Fruchet 	 */
3019d47c4126SHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_RESET02,
3020d47c4126SHugues Fruchet 			     BIT(4) | BIT(3) | BIT(2),
3021d47c4126SHugues Fruchet 			     is_jpeg ? 0 : (BIT(4) | BIT(3) | BIT(2)));
3022d47c4126SHugues Fruchet 	if (ret)
3023d47c4126SHugues Fruchet 		return ret;
3024d47c4126SHugues Fruchet 
3025d47c4126SHugues Fruchet 	/*
3026d47c4126SHugues Fruchet 	 * CLOCK ENABLE02:
3027d47c4126SHugues Fruchet 	 * - [5]:	Enable JPEG 2x clock
3028d47c4126SHugues Fruchet 	 * - [3]:	Enable JPEG clock
3029d47c4126SHugues Fruchet 	 */
3030d47c4126SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_SYS_CLOCK_ENABLE02,
3031d47c4126SHugues Fruchet 			      BIT(5) | BIT(3),
3032d47c4126SHugues Fruchet 			      is_jpeg ? (BIT(5) | BIT(3)) : 0);
3033e3ee691dSHugues Fruchet }
303419a81c14SSteve Longerbeam 
303519a81c14SSteve Longerbeam /*
303619a81c14SSteve Longerbeam  * Sensor Controls.
303719a81c14SSteve Longerbeam  */
303819a81c14SSteve Longerbeam 
303919a81c14SSteve Longerbeam static int ov5640_set_ctrl_hue(struct ov5640_dev *sensor, int value)
304019a81c14SSteve Longerbeam {
304119a81c14SSteve Longerbeam 	int ret;
304219a81c14SSteve Longerbeam 
304319a81c14SSteve Longerbeam 	if (value) {
304419a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
304519a81c14SSteve Longerbeam 				     BIT(0), BIT(0));
304619a81c14SSteve Longerbeam 		if (ret)
304719a81c14SSteve Longerbeam 			return ret;
304819a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_SDE_CTRL1, value);
304919a81c14SSteve Longerbeam 	} else {
305019a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(0), 0);
305119a81c14SSteve Longerbeam 	}
305219a81c14SSteve Longerbeam 
305319a81c14SSteve Longerbeam 	return ret;
305419a81c14SSteve Longerbeam }
305519a81c14SSteve Longerbeam 
305619a81c14SSteve Longerbeam static int ov5640_set_ctrl_contrast(struct ov5640_dev *sensor, int value)
305719a81c14SSteve Longerbeam {
305819a81c14SSteve Longerbeam 	int ret;
305919a81c14SSteve Longerbeam 
306019a81c14SSteve Longerbeam 	if (value) {
306119a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
306219a81c14SSteve Longerbeam 				     BIT(2), BIT(2));
306319a81c14SSteve Longerbeam 		if (ret)
306419a81c14SSteve Longerbeam 			return ret;
306519a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL5,
306619a81c14SSteve Longerbeam 				       value & 0xff);
306719a81c14SSteve Longerbeam 	} else {
306819a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(2), 0);
306919a81c14SSteve Longerbeam 	}
307019a81c14SSteve Longerbeam 
307119a81c14SSteve Longerbeam 	return ret;
307219a81c14SSteve Longerbeam }
307319a81c14SSteve Longerbeam 
307419a81c14SSteve Longerbeam static int ov5640_set_ctrl_saturation(struct ov5640_dev *sensor, int value)
307519a81c14SSteve Longerbeam {
307619a81c14SSteve Longerbeam 	int ret;
307719a81c14SSteve Longerbeam 
307819a81c14SSteve Longerbeam 	if (value) {
307919a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
308019a81c14SSteve Longerbeam 				     BIT(1), BIT(1));
308119a81c14SSteve Longerbeam 		if (ret)
308219a81c14SSteve Longerbeam 			return ret;
308319a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL3,
308419a81c14SSteve Longerbeam 				       value & 0xff);
308519a81c14SSteve Longerbeam 		if (ret)
308619a81c14SSteve Longerbeam 			return ret;
308719a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL4,
308819a81c14SSteve Longerbeam 				       value & 0xff);
308919a81c14SSteve Longerbeam 	} else {
309019a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(1), 0);
309119a81c14SSteve Longerbeam 	}
309219a81c14SSteve Longerbeam 
309319a81c14SSteve Longerbeam 	return ret;
309419a81c14SSteve Longerbeam }
309519a81c14SSteve Longerbeam 
309619a81c14SSteve Longerbeam static int ov5640_set_ctrl_white_balance(struct ov5640_dev *sensor, int awb)
309719a81c14SSteve Longerbeam {
309819a81c14SSteve Longerbeam 	int ret;
309919a81c14SSteve Longerbeam 
310019a81c14SSteve Longerbeam 	ret = ov5640_mod_reg(sensor, OV5640_REG_AWB_MANUAL_CTRL,
310119a81c14SSteve Longerbeam 			     BIT(0), awb ? 0 : 1);
310219a81c14SSteve Longerbeam 	if (ret)
310319a81c14SSteve Longerbeam 		return ret;
310419a81c14SSteve Longerbeam 
310519a81c14SSteve Longerbeam 	if (!awb) {
310619a81c14SSteve Longerbeam 		u16 red = (u16)sensor->ctrls.red_balance->val;
310719a81c14SSteve Longerbeam 		u16 blue = (u16)sensor->ctrls.blue_balance->val;
310819a81c14SSteve Longerbeam 
310919a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_R_GAIN, red);
311019a81c14SSteve Longerbeam 		if (ret)
311119a81c14SSteve Longerbeam 			return ret;
311219a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_B_GAIN, blue);
311319a81c14SSteve Longerbeam 	}
311419a81c14SSteve Longerbeam 
311519a81c14SSteve Longerbeam 	return ret;
311619a81c14SSteve Longerbeam }
311719a81c14SSteve Longerbeam 
31183cca8ef5SHugues Fruchet static int ov5640_set_ctrl_exposure(struct ov5640_dev *sensor,
31193cca8ef5SHugues Fruchet 				    enum v4l2_exposure_auto_type auto_exposure)
312019a81c14SSteve Longerbeam {
312119a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
31223cca8ef5SHugues Fruchet 	bool auto_exp = (auto_exposure == V4L2_EXPOSURE_AUTO);
312319a81c14SSteve Longerbeam 	int ret = 0;
312419a81c14SSteve Longerbeam 
312519a81c14SSteve Longerbeam 	if (ctrls->auto_exp->is_new) {
31263cca8ef5SHugues Fruchet 		ret = ov5640_set_autoexposure(sensor, auto_exp);
312719a81c14SSteve Longerbeam 		if (ret)
312819a81c14SSteve Longerbeam 			return ret;
312919a81c14SSteve Longerbeam 	}
313019a81c14SSteve Longerbeam 
31313cca8ef5SHugues Fruchet 	if (!auto_exp && ctrls->exposure->is_new) {
313219a81c14SSteve Longerbeam 		u16 max_exp;
313319a81c14SSteve Longerbeam 
313419a81c14SSteve Longerbeam 		ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_VTS,
313519a81c14SSteve Longerbeam 					&max_exp);
313619a81c14SSteve Longerbeam 		if (ret)
313719a81c14SSteve Longerbeam 			return ret;
313819a81c14SSteve Longerbeam 		ret = ov5640_get_vts(sensor);
313919a81c14SSteve Longerbeam 		if (ret < 0)
314019a81c14SSteve Longerbeam 			return ret;
314119a81c14SSteve Longerbeam 		max_exp += ret;
31426146fde3SHugues Fruchet 		ret = 0;
314319a81c14SSteve Longerbeam 
314419a81c14SSteve Longerbeam 		if (ctrls->exposure->val < max_exp)
314519a81c14SSteve Longerbeam 			ret = ov5640_set_exposure(sensor, ctrls->exposure->val);
314619a81c14SSteve Longerbeam 	}
314719a81c14SSteve Longerbeam 
314819a81c14SSteve Longerbeam 	return ret;
314919a81c14SSteve Longerbeam }
315019a81c14SSteve Longerbeam 
31513cca8ef5SHugues Fruchet static int ov5640_set_ctrl_gain(struct ov5640_dev *sensor, bool auto_gain)
315219a81c14SSteve Longerbeam {
315319a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
315419a81c14SSteve Longerbeam 	int ret = 0;
315519a81c14SSteve Longerbeam 
315619a81c14SSteve Longerbeam 	if (ctrls->auto_gain->is_new) {
31573cca8ef5SHugues Fruchet 		ret = ov5640_set_autogain(sensor, auto_gain);
315819a81c14SSteve Longerbeam 		if (ret)
315919a81c14SSteve Longerbeam 			return ret;
316019a81c14SSteve Longerbeam 	}
316119a81c14SSteve Longerbeam 
31623cca8ef5SHugues Fruchet 	if (!auto_gain && ctrls->gain->is_new)
31633cca8ef5SHugues Fruchet 		ret = ov5640_set_gain(sensor, ctrls->gain->val);
316419a81c14SSteve Longerbeam 
316519a81c14SSteve Longerbeam 	return ret;
316619a81c14SSteve Longerbeam }
316719a81c14SSteve Longerbeam 
31689f6d7bacSChen-Yu Tsai static const char * const test_pattern_menu[] = {
31699f6d7bacSChen-Yu Tsai 	"Disabled",
31709f6d7bacSChen-Yu Tsai 	"Color bars",
3171bddc5cdfSChen-Yu Tsai 	"Color bars w/ rolling bar",
3172bddc5cdfSChen-Yu Tsai 	"Color squares",
3173bddc5cdfSChen-Yu Tsai 	"Color squares w/ rolling bar",
31749f6d7bacSChen-Yu Tsai };
31759f6d7bacSChen-Yu Tsai 
3176a0c29afbSChen-Yu Tsai #define OV5640_TEST_ENABLE		BIT(7)
3177a0c29afbSChen-Yu Tsai #define OV5640_TEST_ROLLING		BIT(6)	/* rolling horizontal bar */
3178a0c29afbSChen-Yu Tsai #define OV5640_TEST_TRANSPARENT		BIT(5)
3179a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE_BW		BIT(4)	/* black & white squares */
3180a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_STANDARD	(0 << 2)
3181a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_1	(1 << 2)
3182a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_HOR_CHANGE	(2 << 2)
3183a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_2	(3 << 2)
3184a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR			(0 << 0)
3185a0c29afbSChen-Yu Tsai #define OV5640_TEST_RANDOM		(1 << 0)
3186a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE		(2 << 0)
3187a0c29afbSChen-Yu Tsai #define OV5640_TEST_BLACK		(3 << 0)
3188a0c29afbSChen-Yu Tsai 
3189a0c29afbSChen-Yu Tsai static const u8 test_pattern_val[] = {
3190a0c29afbSChen-Yu Tsai 	0,
31912aff1fc3SChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_BAR_VERT_CHANGE_1 |
3192a0c29afbSChen-Yu Tsai 		OV5640_TEST_BAR,
3193bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_ROLLING |
3194bddc5cdfSChen-Yu Tsai 		OV5640_TEST_BAR_VERT_CHANGE_1 | OV5640_TEST_BAR,
3195bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_SQUARE,
3196bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_ROLLING | OV5640_TEST_SQUARE,
3197a0c29afbSChen-Yu Tsai };
3198a0c29afbSChen-Yu Tsai 
319919a81c14SSteve Longerbeam static int ov5640_set_ctrl_test_pattern(struct ov5640_dev *sensor, int value)
320019a81c14SSteve Longerbeam {
3201a0c29afbSChen-Yu Tsai 	return ov5640_write_reg(sensor, OV5640_REG_PRE_ISP_TEST_SET1,
3202a0c29afbSChen-Yu Tsai 				test_pattern_val[value]);
320319a81c14SSteve Longerbeam }
320419a81c14SSteve Longerbeam 
32051068fecaSMylène Josserand static int ov5640_set_ctrl_light_freq(struct ov5640_dev *sensor, int value)
32061068fecaSMylène Josserand {
32071068fecaSMylène Josserand 	int ret;
32081068fecaSMylène Josserand 
32091068fecaSMylène Josserand 	ret = ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL01, BIT(7),
32101068fecaSMylène Josserand 			     (value == V4L2_CID_POWER_LINE_FREQUENCY_AUTO) ?
32111068fecaSMylène Josserand 			     0 : BIT(7));
32121068fecaSMylène Josserand 	if (ret)
32131068fecaSMylène Josserand 		return ret;
32141068fecaSMylène Josserand 
32151068fecaSMylène Josserand 	return ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL00, BIT(2),
32161068fecaSMylène Josserand 			      (value == V4L2_CID_POWER_LINE_FREQUENCY_50HZ) ?
32171068fecaSMylène Josserand 			      BIT(2) : 0);
32181068fecaSMylène Josserand }
32191068fecaSMylène Josserand 
3220ce85705aSHugues Fruchet static int ov5640_set_ctrl_hflip(struct ov5640_dev *sensor, int value)
3221ce85705aSHugues Fruchet {
3222ce85705aSHugues Fruchet 	/*
3223c3f3ba3eSHugues Fruchet 	 * If sensor is mounted upside down, mirror logic is inversed.
3224c3f3ba3eSHugues Fruchet 	 *
3225ce85705aSHugues Fruchet 	 * Sensor is a BSI (Back Side Illuminated) one,
3226ce85705aSHugues Fruchet 	 * so image captured is physically mirrored.
3227ce85705aSHugues Fruchet 	 * This is why mirror logic is inversed in
3228ce85705aSHugues Fruchet 	 * order to cancel this mirror effect.
3229ce85705aSHugues Fruchet 	 */
3230ce85705aSHugues Fruchet 
3231ce85705aSHugues Fruchet 	/*
3232ce85705aSHugues Fruchet 	 * TIMING TC REG21:
3233ce85705aSHugues Fruchet 	 * - [2]:	ISP mirror
3234ce85705aSHugues Fruchet 	 * - [1]:	Sensor mirror
3235ce85705aSHugues Fruchet 	 */
3236ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
3237ce85705aSHugues Fruchet 			      BIT(2) | BIT(1),
3238c3f3ba3eSHugues Fruchet 			      (!(value ^ sensor->upside_down)) ?
3239c3f3ba3eSHugues Fruchet 			      (BIT(2) | BIT(1)) : 0);
3240ce85705aSHugues Fruchet }
3241ce85705aSHugues Fruchet 
3242ce85705aSHugues Fruchet static int ov5640_set_ctrl_vflip(struct ov5640_dev *sensor, int value)
3243ce85705aSHugues Fruchet {
3244c3f3ba3eSHugues Fruchet 	/* If sensor is mounted upside down, flip logic is inversed */
3245c3f3ba3eSHugues Fruchet 
3246ce85705aSHugues Fruchet 	/*
3247ce85705aSHugues Fruchet 	 * TIMING TC REG20:
3248ce85705aSHugues Fruchet 	 * - [2]:	ISP vflip
3249ce85705aSHugues Fruchet 	 * - [1]:	Sensor vflip
3250ce85705aSHugues Fruchet 	 */
3251ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20,
3252ce85705aSHugues Fruchet 			      BIT(2) | BIT(1),
3253c3f3ba3eSHugues Fruchet 			      (value ^ sensor->upside_down) ?
3254c3f3ba3eSHugues Fruchet 			      (BIT(2) | BIT(1)) : 0);
3255ce85705aSHugues Fruchet }
3256ce85705aSHugues Fruchet 
3257bce93b82SJacopo Mondi static int ov5640_set_ctrl_vblank(struct ov5640_dev *sensor, int value)
3258bce93b82SJacopo Mondi {
3259bce93b82SJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
3260bce93b82SJacopo Mondi 
3261bce93b82SJacopo Mondi 	/* Update the VTOT timing register value. */
3262bce93b82SJacopo Mondi 	return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS,
3263bce93b82SJacopo Mondi 				  mode->height + value);
3264bce93b82SJacopo Mondi }
3265bce93b82SJacopo Mondi 
326619a81c14SSteve Longerbeam static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
326719a81c14SSteve Longerbeam {
326819a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
326919a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
327019a81c14SSteve Longerbeam 	int val;
327119a81c14SSteve Longerbeam 
327219a81c14SSteve Longerbeam 	/* v4l2_ctrl_lock() locks our own mutex */
327319a81c14SSteve Longerbeam 
327419a81c14SSteve Longerbeam 	switch (ctrl->id) {
327519a81c14SSteve Longerbeam 	case V4L2_CID_AUTOGAIN:
327619a81c14SSteve Longerbeam 		val = ov5640_get_gain(sensor);
327719a81c14SSteve Longerbeam 		if (val < 0)
327819a81c14SSteve Longerbeam 			return val;
327919a81c14SSteve Longerbeam 		sensor->ctrls.gain->val = val;
328019a81c14SSteve Longerbeam 		break;
328119a81c14SSteve Longerbeam 	case V4L2_CID_EXPOSURE_AUTO:
328219a81c14SSteve Longerbeam 		val = ov5640_get_exposure(sensor);
328319a81c14SSteve Longerbeam 		if (val < 0)
328419a81c14SSteve Longerbeam 			return val;
328519a81c14SSteve Longerbeam 		sensor->ctrls.exposure->val = val;
328619a81c14SSteve Longerbeam 		break;
328719a81c14SSteve Longerbeam 	}
328819a81c14SSteve Longerbeam 
328919a81c14SSteve Longerbeam 	return 0;
329019a81c14SSteve Longerbeam }
329119a81c14SSteve Longerbeam 
329219a81c14SSteve Longerbeam static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl)
329319a81c14SSteve Longerbeam {
329419a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
329519a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
3296bce93b82SJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
3297bce93b82SJacopo Mondi 	const struct ov5640_timings *timings;
3298bce93b82SJacopo Mondi 	unsigned int exp_max;
329919a81c14SSteve Longerbeam 	int ret;
330019a81c14SSteve Longerbeam 
330119a81c14SSteve Longerbeam 	/* v4l2_ctrl_lock() locks our own mutex */
330219a81c14SSteve Longerbeam 
3303bce93b82SJacopo Mondi 	switch (ctrl->id) {
3304bce93b82SJacopo Mondi 	case V4L2_CID_VBLANK:
3305bce93b82SJacopo Mondi 		/* Update the exposure range to the newly programmed vblank. */
3306bce93b82SJacopo Mondi 		timings = ov5640_timings(sensor, mode);
3307bce93b82SJacopo Mondi 		exp_max = mode->height + ctrl->val - 4;
3308bce93b82SJacopo Mondi 		__v4l2_ctrl_modify_range(sensor->ctrls.exposure,
3309bce93b82SJacopo Mondi 					 sensor->ctrls.exposure->minimum,
3310bce93b82SJacopo Mondi 					 exp_max, sensor->ctrls.exposure->step,
3311bce93b82SJacopo Mondi 					 timings->vblank_def);
3312bce93b82SJacopo Mondi 		break;
3313bce93b82SJacopo Mondi 	}
3314bce93b82SJacopo Mondi 
331519a81c14SSteve Longerbeam 	/*
331619a81c14SSteve Longerbeam 	 * If the device is not powered up by the host driver do
331719a81c14SSteve Longerbeam 	 * not apply any controls to H/W at this time. Instead
331819a81c14SSteve Longerbeam 	 * the controls will be restored right after power-up.
331919a81c14SSteve Longerbeam 	 */
332019a81c14SSteve Longerbeam 	if (sensor->power_count == 0)
332119a81c14SSteve Longerbeam 		return 0;
332219a81c14SSteve Longerbeam 
332319a81c14SSteve Longerbeam 	switch (ctrl->id) {
332419a81c14SSteve Longerbeam 	case V4L2_CID_AUTOGAIN:
332519a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_gain(sensor, ctrl->val);
332619a81c14SSteve Longerbeam 		break;
332719a81c14SSteve Longerbeam 	case V4L2_CID_EXPOSURE_AUTO:
332819a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_exposure(sensor, ctrl->val);
332919a81c14SSteve Longerbeam 		break;
333019a81c14SSteve Longerbeam 	case V4L2_CID_AUTO_WHITE_BALANCE:
333119a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_white_balance(sensor, ctrl->val);
333219a81c14SSteve Longerbeam 		break;
333319a81c14SSteve Longerbeam 	case V4L2_CID_HUE:
333419a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_hue(sensor, ctrl->val);
333519a81c14SSteve Longerbeam 		break;
333619a81c14SSteve Longerbeam 	case V4L2_CID_CONTRAST:
333719a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_contrast(sensor, ctrl->val);
333819a81c14SSteve Longerbeam 		break;
333919a81c14SSteve Longerbeam 	case V4L2_CID_SATURATION:
334019a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_saturation(sensor, ctrl->val);
334119a81c14SSteve Longerbeam 		break;
334219a81c14SSteve Longerbeam 	case V4L2_CID_TEST_PATTERN:
334319a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_test_pattern(sensor, ctrl->val);
334419a81c14SSteve Longerbeam 		break;
33451068fecaSMylène Josserand 	case V4L2_CID_POWER_LINE_FREQUENCY:
33461068fecaSMylène Josserand 		ret = ov5640_set_ctrl_light_freq(sensor, ctrl->val);
33471068fecaSMylène Josserand 		break;
3348ce85705aSHugues Fruchet 	case V4L2_CID_HFLIP:
3349ce85705aSHugues Fruchet 		ret = ov5640_set_ctrl_hflip(sensor, ctrl->val);
3350ce85705aSHugues Fruchet 		break;
3351ce85705aSHugues Fruchet 	case V4L2_CID_VFLIP:
3352ce85705aSHugues Fruchet 		ret = ov5640_set_ctrl_vflip(sensor, ctrl->val);
3353ce85705aSHugues Fruchet 		break;
3354bce93b82SJacopo Mondi 	case V4L2_CID_VBLANK:
3355bce93b82SJacopo Mondi 		ret = ov5640_set_ctrl_vblank(sensor, ctrl->val);
3356bce93b82SJacopo Mondi 		break;
335719a81c14SSteve Longerbeam 	default:
335819a81c14SSteve Longerbeam 		ret = -EINVAL;
335919a81c14SSteve Longerbeam 		break;
336019a81c14SSteve Longerbeam 	}
336119a81c14SSteve Longerbeam 
336219a81c14SSteve Longerbeam 	return ret;
336319a81c14SSteve Longerbeam }
336419a81c14SSteve Longerbeam 
336519a81c14SSteve Longerbeam static const struct v4l2_ctrl_ops ov5640_ctrl_ops = {
336619a81c14SSteve Longerbeam 	.g_volatile_ctrl = ov5640_g_volatile_ctrl,
336719a81c14SSteve Longerbeam 	.s_ctrl = ov5640_s_ctrl,
336819a81c14SSteve Longerbeam };
336919a81c14SSteve Longerbeam 
337019a81c14SSteve Longerbeam static int ov5640_init_controls(struct ov5640_dev *sensor)
337119a81c14SSteve Longerbeam {
337222845bf2SJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
337319a81c14SSteve Longerbeam 	const struct v4l2_ctrl_ops *ops = &ov5640_ctrl_ops;
337419a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
337519a81c14SSteve Longerbeam 	struct v4l2_ctrl_handler *hdl = &ctrls->handler;
33761066fc1cSJacopo Mondi 	struct v4l2_fwnode_device_properties props;
337732979f67SJacopo Mondi 	const struct ov5640_timings *timings;
3378bce93b82SJacopo Mondi 	unsigned int max_vblank;
337932979f67SJacopo Mondi 	unsigned int hblank;
338019a81c14SSteve Longerbeam 	int ret;
338119a81c14SSteve Longerbeam 
338219a81c14SSteve Longerbeam 	v4l2_ctrl_handler_init(hdl, 32);
338319a81c14SSteve Longerbeam 
338419a81c14SSteve Longerbeam 	/* we can use our own mutex for the ctrl lock */
338519a81c14SSteve Longerbeam 	hdl->lock = &sensor->lock;
338619a81c14SSteve Longerbeam 
3387cc196e48SBenoit Parrot 	/* Clock related controls */
3388cc196e48SBenoit Parrot 	ctrls->pixel_rate = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE,
338922845bf2SJacopo Mondi 			      ov5640_pixel_rates[OV5640_NUM_PIXEL_RATES - 1],
339022845bf2SJacopo Mondi 			      ov5640_pixel_rates[0], 1,
339122845bf2SJacopo Mondi 			      ov5640_pixel_rates[mode->pixel_rate]);
3392cc196e48SBenoit Parrot 
33937a3b8d4bSJacopo Mondi 	ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops,
33947a3b8d4bSJacopo Mondi 					V4L2_CID_LINK_FREQ,
33957a3b8d4bSJacopo Mondi 					ARRAY_SIZE(ov5640_csi2_link_freqs) - 1,
33967a3b8d4bSJacopo Mondi 					OV5640_DEFAULT_LINK_FREQ,
33977a3b8d4bSJacopo Mondi 					ov5640_csi2_link_freqs);
33987a3b8d4bSJacopo Mondi 
339932979f67SJacopo Mondi 	timings = ov5640_timings(sensor, mode);
340032979f67SJacopo Mondi 	hblank = timings->htot - mode->width;
340132979f67SJacopo Mondi 	ctrls->hblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HBLANK, hblank,
340232979f67SJacopo Mondi 					  hblank, 1, hblank);
340332979f67SJacopo Mondi 
3404bce93b82SJacopo Mondi 	max_vblank = OV5640_MAX_VTS - mode->height;
3405bce93b82SJacopo Mondi 	ctrls->vblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VBLANK,
3406bce93b82SJacopo Mondi 					  OV5640_MIN_VBLANK, max_vblank,
3407bce93b82SJacopo Mondi 					  1, timings->vblank_def);
3408bce93b82SJacopo Mondi 
340919a81c14SSteve Longerbeam 	/* Auto/manual white balance */
341019a81c14SSteve Longerbeam 	ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops,
341119a81c14SSteve Longerbeam 					   V4L2_CID_AUTO_WHITE_BALANCE,
341219a81c14SSteve Longerbeam 					   0, 1, 1, 1);
341319a81c14SSteve Longerbeam 	ctrls->blue_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BLUE_BALANCE,
341419a81c14SSteve Longerbeam 						0, 4095, 1, 0);
341519a81c14SSteve Longerbeam 	ctrls->red_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_RED_BALANCE,
341619a81c14SSteve Longerbeam 					       0, 4095, 1, 0);
341719a81c14SSteve Longerbeam 	/* Auto/manual exposure */
341819a81c14SSteve Longerbeam 	ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops,
341919a81c14SSteve Longerbeam 						 V4L2_CID_EXPOSURE_AUTO,
342019a81c14SSteve Longerbeam 						 V4L2_EXPOSURE_MANUAL, 0,
342119a81c14SSteve Longerbeam 						 V4L2_EXPOSURE_AUTO);
342219a81c14SSteve Longerbeam 	ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
342319a81c14SSteve Longerbeam 					    0, 65535, 1, 0);
342419a81c14SSteve Longerbeam 	/* Auto/manual gain */
342519a81c14SSteve Longerbeam 	ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN,
342619a81c14SSteve Longerbeam 					     0, 1, 1, 1);
342719a81c14SSteve Longerbeam 	ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN,
342819a81c14SSteve Longerbeam 					0, 1023, 1, 0);
342919a81c14SSteve Longerbeam 
343019a81c14SSteve Longerbeam 	ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION,
343119a81c14SSteve Longerbeam 					      0, 255, 1, 64);
343219a81c14SSteve Longerbeam 	ctrls->hue = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HUE,
343319a81c14SSteve Longerbeam 				       0, 359, 1, 0);
343419a81c14SSteve Longerbeam 	ctrls->contrast = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST,
343519a81c14SSteve Longerbeam 					    0, 255, 1, 0);
343619a81c14SSteve Longerbeam 	ctrls->test_pattern =
343719a81c14SSteve Longerbeam 		v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN,
343819a81c14SSteve Longerbeam 					     ARRAY_SIZE(test_pattern_menu) - 1,
343919a81c14SSteve Longerbeam 					     0, 0, test_pattern_menu);
3440ce85705aSHugues Fruchet 	ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP,
3441ce85705aSHugues Fruchet 					 0, 1, 1, 0);
3442ce85705aSHugues Fruchet 	ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP,
3443ce85705aSHugues Fruchet 					 0, 1, 1, 0);
344419a81c14SSteve Longerbeam 
34451068fecaSMylène Josserand 	ctrls->light_freq =
34461068fecaSMylène Josserand 		v4l2_ctrl_new_std_menu(hdl, ops,
34471068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY,
34481068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
34491068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
34501068fecaSMylène Josserand 
345119a81c14SSteve Longerbeam 	if (hdl->error) {
345219a81c14SSteve Longerbeam 		ret = hdl->error;
345319a81c14SSteve Longerbeam 		goto free_ctrls;
345419a81c14SSteve Longerbeam 	}
345519a81c14SSteve Longerbeam 
34561066fc1cSJacopo Mondi 	ret = v4l2_fwnode_device_parse(&sensor->i2c_client->dev, &props);
34571066fc1cSJacopo Mondi 	if (ret)
34581066fc1cSJacopo Mondi 		goto free_ctrls;
34591066fc1cSJacopo Mondi 
34601066fc1cSJacopo Mondi 	if (props.rotation == 180)
34611066fc1cSJacopo Mondi 		sensor->upside_down = true;
34621066fc1cSJacopo Mondi 
34631066fc1cSJacopo Mondi 	ret = v4l2_ctrl_new_fwnode_properties(hdl, ops, &props);
34641066fc1cSJacopo Mondi 	if (ret)
34651066fc1cSJacopo Mondi 		goto free_ctrls;
34661066fc1cSJacopo Mondi 
3467cc196e48SBenoit Parrot 	ctrls->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY;
34687a3b8d4bSJacopo Mondi 	ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
346932979f67SJacopo Mondi 	ctrls->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
347019a81c14SSteve Longerbeam 	ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE;
347119a81c14SSteve Longerbeam 	ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE;
347219a81c14SSteve Longerbeam 
347319a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false);
347419a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(2, &ctrls->auto_gain, 0, true);
347519a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(2, &ctrls->auto_exp, 1, true);
347619a81c14SSteve Longerbeam 
347719a81c14SSteve Longerbeam 	sensor->sd.ctrl_handler = hdl;
347819a81c14SSteve Longerbeam 	return 0;
347919a81c14SSteve Longerbeam 
348019a81c14SSteve Longerbeam free_ctrls:
348119a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(hdl);
348219a81c14SSteve Longerbeam 	return ret;
348319a81c14SSteve Longerbeam }
348419a81c14SSteve Longerbeam 
348519a81c14SSteve Longerbeam static int ov5640_enum_frame_size(struct v4l2_subdev *sd,
34860d346d2aSTomi Valkeinen 				  struct v4l2_subdev_state *sd_state,
348719a81c14SSteve Longerbeam 				  struct v4l2_subdev_frame_size_enum *fse)
348819a81c14SSteve Longerbeam {
34897dcb3a2fSJacopo Mondi 	u32 bpp = ov5640_code_to_bpp(fse->code);
34907dcb3a2fSJacopo Mondi 	unsigned int index = fse->index;
34917dcb3a2fSJacopo Mondi 
349219a81c14SSteve Longerbeam 	if (fse->pad != 0)
349319a81c14SSteve Longerbeam 		return -EINVAL;
34947dcb3a2fSJacopo Mondi 	if (!bpp)
349519a81c14SSteve Longerbeam 		return -EINVAL;
349619a81c14SSteve Longerbeam 
34977dcb3a2fSJacopo Mondi 	/* Only low-resolution modes are supported for 24bpp formats. */
34987dcb3a2fSJacopo Mondi 	if (bpp == 24 && index >= OV5640_MODE_720P_1280_720)
34997dcb3a2fSJacopo Mondi 		return -EINVAL;
35007dcb3a2fSJacopo Mondi 
35017dcb3a2fSJacopo Mondi 	/* FIXME: Low resolution modes don't work in 8bpp formats. */
35027dcb3a2fSJacopo Mondi 	if (bpp == 8)
35037dcb3a2fSJacopo Mondi 		index += OV5640_MODE_720P_1280_720;
35047dcb3a2fSJacopo Mondi 
35057dcb3a2fSJacopo Mondi 	if (index >= OV5640_NUM_MODES)
35067dcb3a2fSJacopo Mondi 		return -EINVAL;
35077dcb3a2fSJacopo Mondi 
35087dcb3a2fSJacopo Mondi 	fse->min_width = ov5640_mode_data[index].width;
350941d8d7f5SHugues Fruchet 	fse->max_width = fse->min_width;
35107dcb3a2fSJacopo Mondi 	fse->min_height = ov5640_mode_data[index].height;
351141d8d7f5SHugues Fruchet 	fse->max_height = fse->min_height;
351219a81c14SSteve Longerbeam 
351319a81c14SSteve Longerbeam 	return 0;
351419a81c14SSteve Longerbeam }
351519a81c14SSteve Longerbeam 
351619a81c14SSteve Longerbeam static int ov5640_enum_frame_interval(
351719a81c14SSteve Longerbeam 	struct v4l2_subdev *sd,
35180d346d2aSTomi Valkeinen 	struct v4l2_subdev_state *sd_state,
351919a81c14SSteve Longerbeam 	struct v4l2_subdev_frame_interval_enum *fie)
352019a81c14SSteve Longerbeam {
352119a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
352219a81c14SSteve Longerbeam 	struct v4l2_fract tpf;
352319a81c14SSteve Longerbeam 	int ret;
352419a81c14SSteve Longerbeam 
352519a81c14SSteve Longerbeam 	if (fie->pad != 0)
352619a81c14SSteve Longerbeam 		return -EINVAL;
352719a81c14SSteve Longerbeam 	if (fie->index >= OV5640_NUM_FRAMERATES)
352819a81c14SSteve Longerbeam 		return -EINVAL;
352919a81c14SSteve Longerbeam 
353019a81c14SSteve Longerbeam 	tpf.numerator = 1;
353119a81c14SSteve Longerbeam 	tpf.denominator = ov5640_framerates[fie->index];
353219a81c14SSteve Longerbeam 
353319a81c14SSteve Longerbeam 	ret = ov5640_try_frame_interval(sensor, &tpf,
353419a81c14SSteve Longerbeam 					fie->width, fie->height);
353519a81c14SSteve Longerbeam 	if (ret < 0)
353619a81c14SSteve Longerbeam 		return -EINVAL;
353719a81c14SSteve Longerbeam 
353819a81c14SSteve Longerbeam 	fie->interval = tpf;
353919a81c14SSteve Longerbeam 	return 0;
354019a81c14SSteve Longerbeam }
354119a81c14SSteve Longerbeam 
354219a81c14SSteve Longerbeam static int ov5640_g_frame_interval(struct v4l2_subdev *sd,
354319a81c14SSteve Longerbeam 				   struct v4l2_subdev_frame_interval *fi)
354419a81c14SSteve Longerbeam {
354519a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
354619a81c14SSteve Longerbeam 
354719a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
354819a81c14SSteve Longerbeam 	fi->interval = sensor->frame_interval;
354919a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
355019a81c14SSteve Longerbeam 
355119a81c14SSteve Longerbeam 	return 0;
355219a81c14SSteve Longerbeam }
355319a81c14SSteve Longerbeam 
355419a81c14SSteve Longerbeam static int ov5640_s_frame_interval(struct v4l2_subdev *sd,
355519a81c14SSteve Longerbeam 				   struct v4l2_subdev_frame_interval *fi)
355619a81c14SSteve Longerbeam {
355719a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
355819a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
355919a81c14SSteve Longerbeam 	int frame_rate, ret = 0;
356019a81c14SSteve Longerbeam 
356119a81c14SSteve Longerbeam 	if (fi->pad != 0)
356219a81c14SSteve Longerbeam 		return -EINVAL;
356319a81c14SSteve Longerbeam 
356419a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
356519a81c14SSteve Longerbeam 
356619a81c14SSteve Longerbeam 	if (sensor->streaming) {
356719a81c14SSteve Longerbeam 		ret = -EBUSY;
356819a81c14SSteve Longerbeam 		goto out;
356919a81c14SSteve Longerbeam 	}
357019a81c14SSteve Longerbeam 
357119a81c14SSteve Longerbeam 	mode = sensor->current_mode;
357219a81c14SSteve Longerbeam 
357319a81c14SSteve Longerbeam 	frame_rate = ov5640_try_frame_interval(sensor, &fi->interval,
35745113d5b3SJacopo Mondi 					       mode->width,
35755113d5b3SJacopo Mondi 					       mode->height);
3576e823fb16SMaxime Ripard 	if (frame_rate < 0) {
3577e823fb16SMaxime Ripard 		/* Always return a valid frame interval value */
3578e823fb16SMaxime Ripard 		fi->interval = sensor->frame_interval;
3579e823fb16SMaxime Ripard 		goto out;
3580e823fb16SMaxime Ripard 	}
358119a81c14SSteve Longerbeam 
3582b6ae5022SJacopo Mondi 	mode = ov5640_find_mode(sensor, mode->width, mode->height, true);
35833c4a7372SHugues Fruchet 	if (!mode) {
35843c4a7372SHugues Fruchet 		ret = -EINVAL;
35853c4a7372SHugues Fruchet 		goto out;
35863c4a7372SHugues Fruchet 	}
35873c4a7372SHugues Fruchet 
3588b6ae5022SJacopo Mondi 	if (ov5640_framerates[frame_rate] > ov5640_framerates[mode->max_fps]) {
3589b6ae5022SJacopo Mondi 		ret = -EINVAL;
3590b6ae5022SJacopo Mondi 		goto out;
3591b6ae5022SJacopo Mondi 	}
3592b6ae5022SJacopo Mondi 
35930929983eSHugues Fruchet 	if (mode != sensor->current_mode ||
35940929983eSHugues Fruchet 	    frame_rate != sensor->current_fr) {
35950929983eSHugues Fruchet 		sensor->current_fr = frame_rate;
35960929983eSHugues Fruchet 		sensor->frame_interval = fi->interval;
35973c4a7372SHugues Fruchet 		sensor->current_mode = mode;
359819a81c14SSteve Longerbeam 		sensor->pending_mode_change = true;
3599cc196e48SBenoit Parrot 
360019f2e3e6SHugues Fruchet 		ov5640_update_pixel_rate(sensor);
36016949d864SHugues Fruchet 	}
360219a81c14SSteve Longerbeam out:
360319a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
360419a81c14SSteve Longerbeam 	return ret;
360519a81c14SSteve Longerbeam }
360619a81c14SSteve Longerbeam 
360719a81c14SSteve Longerbeam static int ov5640_enum_mbus_code(struct v4l2_subdev *sd,
36080d346d2aSTomi Valkeinen 				 struct v4l2_subdev_state *sd_state,
360919a81c14SSteve Longerbeam 				 struct v4l2_subdev_mbus_code_enum *code)
361019a81c14SSteve Longerbeam {
361119a81c14SSteve Longerbeam 	if (code->pad != 0)
361219a81c14SSteve Longerbeam 		return -EINVAL;
3613e3ee691dSHugues Fruchet 	if (code->index >= ARRAY_SIZE(ov5640_formats))
361419a81c14SSteve Longerbeam 		return -EINVAL;
361519a81c14SSteve Longerbeam 
3616e3ee691dSHugues Fruchet 	code->code = ov5640_formats[code->index].code;
361719a81c14SSteve Longerbeam 	return 0;
361819a81c14SSteve Longerbeam }
361919a81c14SSteve Longerbeam 
362019a81c14SSteve Longerbeam static int ov5640_s_stream(struct v4l2_subdev *sd, int enable)
362119a81c14SSteve Longerbeam {
362219a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
362319a81c14SSteve Longerbeam 	int ret = 0;
362419a81c14SSteve Longerbeam 
362519a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
362619a81c14SSteve Longerbeam 
362719a81c14SSteve Longerbeam 	if (sensor->streaming == !enable) {
362819a81c14SSteve Longerbeam 		if (enable && sensor->pending_mode_change) {
3629985cdcb0SHugues Fruchet 			ret = ov5640_set_mode(sensor);
363019a81c14SSteve Longerbeam 			if (ret)
363119a81c14SSteve Longerbeam 				goto out;
3632fb98e29fSHugues Fruchet 		}
3633e3ee691dSHugues Fruchet 
3634fb98e29fSHugues Fruchet 		if (enable && sensor->pending_fmt_change) {
3635e3ee691dSHugues Fruchet 			ret = ov5640_set_framefmt(sensor, &sensor->fmt);
3636e3ee691dSHugues Fruchet 			if (ret)
3637e3ee691dSHugues Fruchet 				goto out;
3638fb98e29fSHugues Fruchet 			sensor->pending_fmt_change = false;
363919a81c14SSteve Longerbeam 		}
364019a81c14SSteve Longerbeam 
36418e823f5cSJacopo Mondi 		if (ov5640_is_csi2(sensor))
3642f22996dbSHugues Fruchet 			ret = ov5640_set_stream_mipi(sensor, enable);
3643f22996dbSHugues Fruchet 		else
3644f22996dbSHugues Fruchet 			ret = ov5640_set_stream_dvp(sensor, enable);
3645f22996dbSHugues Fruchet 
364619a81c14SSteve Longerbeam 		if (!ret)
364719a81c14SSteve Longerbeam 			sensor->streaming = enable;
364819a81c14SSteve Longerbeam 	}
364919a81c14SSteve Longerbeam out:
365019a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
365119a81c14SSteve Longerbeam 	return ret;
365219a81c14SSteve Longerbeam }
365319a81c14SSteve Longerbeam 
365490b0f355SJacopo Mondi static int ov5640_init_cfg(struct v4l2_subdev *sd,
365590b0f355SJacopo Mondi 			   struct v4l2_subdev_state *state)
365690b0f355SJacopo Mondi {
365790b0f355SJacopo Mondi 	struct v4l2_mbus_framefmt *fmt =
365890b0f355SJacopo Mondi 				v4l2_subdev_get_try_format(sd, state, 0);
365966ed85ebSJacopo Mondi 	struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, state, 0);
366090b0f355SJacopo Mondi 
366190b0f355SJacopo Mondi 	*fmt = ov5640_default_fmt;
366290b0f355SJacopo Mondi 
366366ed85ebSJacopo Mondi 	crop->left = OV5640_PIXEL_ARRAY_LEFT;
366466ed85ebSJacopo Mondi 	crop->top = OV5640_PIXEL_ARRAY_TOP;
366566ed85ebSJacopo Mondi 	crop->width = OV5640_PIXEL_ARRAY_WIDTH;
366666ed85ebSJacopo Mondi 	crop->height = OV5640_PIXEL_ARRAY_HEIGHT;
366766ed85ebSJacopo Mondi 
366890b0f355SJacopo Mondi 	return 0;
366990b0f355SJacopo Mondi }
367090b0f355SJacopo Mondi 
367119a81c14SSteve Longerbeam static const struct v4l2_subdev_core_ops ov5640_core_ops = {
367219a81c14SSteve Longerbeam 	.s_power = ov5640_s_power,
36732d18fbc5SAkinobu Mita 	.log_status = v4l2_ctrl_subdev_log_status,
36742d18fbc5SAkinobu Mita 	.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
36752d18fbc5SAkinobu Mita 	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
367619a81c14SSteve Longerbeam };
367719a81c14SSteve Longerbeam 
367819a81c14SSteve Longerbeam static const struct v4l2_subdev_video_ops ov5640_video_ops = {
367919a81c14SSteve Longerbeam 	.g_frame_interval = ov5640_g_frame_interval,
368019a81c14SSteve Longerbeam 	.s_frame_interval = ov5640_s_frame_interval,
368119a81c14SSteve Longerbeam 	.s_stream = ov5640_s_stream,
368219a81c14SSteve Longerbeam };
368319a81c14SSteve Longerbeam 
368419a81c14SSteve Longerbeam static const struct v4l2_subdev_pad_ops ov5640_pad_ops = {
368590b0f355SJacopo Mondi 	.init_cfg = ov5640_init_cfg,
368619a81c14SSteve Longerbeam 	.enum_mbus_code = ov5640_enum_mbus_code,
368719a81c14SSteve Longerbeam 	.get_fmt = ov5640_get_fmt,
368819a81c14SSteve Longerbeam 	.set_fmt = ov5640_set_fmt,
368966ed85ebSJacopo Mondi 	.get_selection = ov5640_get_selection,
369019a81c14SSteve Longerbeam 	.enum_frame_size = ov5640_enum_frame_size,
369119a81c14SSteve Longerbeam 	.enum_frame_interval = ov5640_enum_frame_interval,
369219a81c14SSteve Longerbeam };
369319a81c14SSteve Longerbeam 
369419a81c14SSteve Longerbeam static const struct v4l2_subdev_ops ov5640_subdev_ops = {
369519a81c14SSteve Longerbeam 	.core = &ov5640_core_ops,
369619a81c14SSteve Longerbeam 	.video = &ov5640_video_ops,
369719a81c14SSteve Longerbeam 	.pad = &ov5640_pad_ops,
369819a81c14SSteve Longerbeam };
369919a81c14SSteve Longerbeam 
370019a81c14SSteve Longerbeam static int ov5640_get_regulators(struct ov5640_dev *sensor)
370119a81c14SSteve Longerbeam {
370219a81c14SSteve Longerbeam 	int i;
370319a81c14SSteve Longerbeam 
370419a81c14SSteve Longerbeam 	for (i = 0; i < OV5640_NUM_SUPPLIES; i++)
370519a81c14SSteve Longerbeam 		sensor->supplies[i].supply = ov5640_supply_name[i];
370619a81c14SSteve Longerbeam 
370719a81c14SSteve Longerbeam 	return devm_regulator_bulk_get(&sensor->i2c_client->dev,
370819a81c14SSteve Longerbeam 				       OV5640_NUM_SUPPLIES,
370919a81c14SSteve Longerbeam 				       sensor->supplies);
371019a81c14SSteve Longerbeam }
371119a81c14SSteve Longerbeam 
37120f7acb52SHugues Fruchet static int ov5640_check_chip_id(struct ov5640_dev *sensor)
37130f7acb52SHugues Fruchet {
37140f7acb52SHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
37150f7acb52SHugues Fruchet 	int ret = 0;
37160f7acb52SHugues Fruchet 	u16 chip_id;
37170f7acb52SHugues Fruchet 
37180f7acb52SHugues Fruchet 	ret = ov5640_set_power_on(sensor);
37190f7acb52SHugues Fruchet 	if (ret)
37200f7acb52SHugues Fruchet 		return ret;
37210f7acb52SHugues Fruchet 
37220f7acb52SHugues Fruchet 	ret = ov5640_read_reg16(sensor, OV5640_REG_CHIP_ID, &chip_id);
37230f7acb52SHugues Fruchet 	if (ret) {
37240f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to read chip identifier\n",
37250f7acb52SHugues Fruchet 			__func__);
37260f7acb52SHugues Fruchet 		goto power_off;
37270f7acb52SHugues Fruchet 	}
37280f7acb52SHugues Fruchet 
37290f7acb52SHugues Fruchet 	if (chip_id != 0x5640) {
37300f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: wrong chip identifier, expected 0x5640, got 0x%x\n",
37310f7acb52SHugues Fruchet 			__func__, chip_id);
37320f7acb52SHugues Fruchet 		ret = -ENXIO;
37330f7acb52SHugues Fruchet 	}
37340f7acb52SHugues Fruchet 
37350f7acb52SHugues Fruchet power_off:
37360f7acb52SHugues Fruchet 	ov5640_set_power_off(sensor);
37370f7acb52SHugues Fruchet 	return ret;
37380f7acb52SHugues Fruchet }
37390f7acb52SHugues Fruchet 
3740e6714993SKieran Bingham static int ov5640_probe(struct i2c_client *client)
374119a81c14SSteve Longerbeam {
374219a81c14SSteve Longerbeam 	struct device *dev = &client->dev;
374319a81c14SSteve Longerbeam 	struct fwnode_handle *endpoint;
374419a81c14SSteve Longerbeam 	struct ov5640_dev *sensor;
374519a81c14SSteve Longerbeam 	int ret;
374619a81c14SSteve Longerbeam 
374719a81c14SSteve Longerbeam 	sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
374819a81c14SSteve Longerbeam 	if (!sensor)
374919a81c14SSteve Longerbeam 		return -ENOMEM;
375019a81c14SSteve Longerbeam 
375119a81c14SSteve Longerbeam 	sensor->i2c_client = client;
3752fb98e29fSHugues Fruchet 
3753fb98e29fSHugues Fruchet 	/*
3754fb98e29fSHugues Fruchet 	 * default init sequence initialize sensor to
3755fb98e29fSHugues Fruchet 	 * YUV422 UYVY VGA@30fps
3756fb98e29fSHugues Fruchet 	 */
375790b0f355SJacopo Mondi 	sensor->fmt = ov5640_default_fmt;
375819a81c14SSteve Longerbeam 	sensor->frame_interval.numerator = 1;
375919a81c14SSteve Longerbeam 	sensor->frame_interval.denominator = ov5640_framerates[OV5640_30_FPS];
376019a81c14SSteve Longerbeam 	sensor->current_fr = OV5640_30_FPS;
376119a81c14SSteve Longerbeam 	sensor->current_mode =
3762086c25f8SMaxime Ripard 		&ov5640_mode_data[OV5640_MODE_VGA_640_480];
3763985cdcb0SHugues Fruchet 	sensor->last_mode = sensor->current_mode;
37643c28588fSJacopo Mondi 	sensor->current_link_freq = OV5640_DEFAULT_LINK_FREQ;
376519a81c14SSteve Longerbeam 
376619a81c14SSteve Longerbeam 	sensor->ae_target = 52;
376719a81c14SSteve Longerbeam 
3768ce96bcf5SSakari Ailus 	endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev),
3769ce96bcf5SSakari Ailus 						  NULL);
377019a81c14SSteve Longerbeam 	if (!endpoint) {
377119a81c14SSteve Longerbeam 		dev_err(dev, "endpoint node not found\n");
377219a81c14SSteve Longerbeam 		return -EINVAL;
377319a81c14SSteve Longerbeam 	}
377419a81c14SSteve Longerbeam 
377519a81c14SSteve Longerbeam 	ret = v4l2_fwnode_endpoint_parse(endpoint, &sensor->ep);
377619a81c14SSteve Longerbeam 	fwnode_handle_put(endpoint);
377719a81c14SSteve Longerbeam 	if (ret) {
377819a81c14SSteve Longerbeam 		dev_err(dev, "Could not parse endpoint\n");
377919a81c14SSteve Longerbeam 		return ret;
378019a81c14SSteve Longerbeam 	}
378119a81c14SSteve Longerbeam 
37822c61e48dSLad Prabhakar 	if (sensor->ep.bus_type != V4L2_MBUS_PARALLEL &&
37832c61e48dSLad Prabhakar 	    sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY &&
37842c61e48dSLad Prabhakar 	    sensor->ep.bus_type != V4L2_MBUS_BT656) {
37852c61e48dSLad Prabhakar 		dev_err(dev, "Unsupported bus type %d\n", sensor->ep.bus_type);
37862c61e48dSLad Prabhakar 		return -EINVAL;
37872c61e48dSLad Prabhakar 	}
37882c61e48dSLad Prabhakar 
378919a81c14SSteve Longerbeam 	/* get system clock (xclk) */
379019a81c14SSteve Longerbeam 	sensor->xclk = devm_clk_get(dev, "xclk");
379119a81c14SSteve Longerbeam 	if (IS_ERR(sensor->xclk)) {
379219a81c14SSteve Longerbeam 		dev_err(dev, "failed to get xclk\n");
379319a81c14SSteve Longerbeam 		return PTR_ERR(sensor->xclk);
379419a81c14SSteve Longerbeam 	}
379519a81c14SSteve Longerbeam 
379619a81c14SSteve Longerbeam 	sensor->xclk_freq = clk_get_rate(sensor->xclk);
379719a81c14SSteve Longerbeam 	if (sensor->xclk_freq < OV5640_XCLK_MIN ||
379819a81c14SSteve Longerbeam 	    sensor->xclk_freq > OV5640_XCLK_MAX) {
379919a81c14SSteve Longerbeam 		dev_err(dev, "xclk frequency out of range: %d Hz\n",
380019a81c14SSteve Longerbeam 			sensor->xclk_freq);
380119a81c14SSteve Longerbeam 		return -EINVAL;
380219a81c14SSteve Longerbeam 	}
380319a81c14SSteve Longerbeam 
380419a81c14SSteve Longerbeam 	/* request optional power down pin */
380519a81c14SSteve Longerbeam 	sensor->pwdn_gpio = devm_gpiod_get_optional(dev, "powerdown",
380619a81c14SSteve Longerbeam 						    GPIOD_OUT_HIGH);
38078791a102SFabio Estevam 	if (IS_ERR(sensor->pwdn_gpio))
38088791a102SFabio Estevam 		return PTR_ERR(sensor->pwdn_gpio);
38098791a102SFabio Estevam 
381019a81c14SSteve Longerbeam 	/* request optional reset pin */
381119a81c14SSteve Longerbeam 	sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset",
381219a81c14SSteve Longerbeam 						     GPIOD_OUT_HIGH);
38138791a102SFabio Estevam 	if (IS_ERR(sensor->reset_gpio))
38148791a102SFabio Estevam 		return PTR_ERR(sensor->reset_gpio);
381519a81c14SSteve Longerbeam 
381619a81c14SSteve Longerbeam 	v4l2_i2c_subdev_init(&sensor->sd, client, &ov5640_subdev_ops);
381719a81c14SSteve Longerbeam 
38182d18fbc5SAkinobu Mita 	sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
38192d18fbc5SAkinobu Mita 			    V4L2_SUBDEV_FL_HAS_EVENTS;
382019a81c14SSteve Longerbeam 	sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
382119a81c14SSteve Longerbeam 	sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
382219a81c14SSteve Longerbeam 	ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
382319a81c14SSteve Longerbeam 	if (ret)
382419a81c14SSteve Longerbeam 		return ret;
382519a81c14SSteve Longerbeam 
382619a81c14SSteve Longerbeam 	ret = ov5640_get_regulators(sensor);
382719a81c14SSteve Longerbeam 	if (ret)
382819a81c14SSteve Longerbeam 		return ret;
382919a81c14SSteve Longerbeam 
383019a81c14SSteve Longerbeam 	mutex_init(&sensor->lock);
383119a81c14SSteve Longerbeam 
38320f7acb52SHugues Fruchet 	ret = ov5640_check_chip_id(sensor);
38330f7acb52SHugues Fruchet 	if (ret)
38340f7acb52SHugues Fruchet 		goto entity_cleanup;
38350f7acb52SHugues Fruchet 
383619a81c14SSteve Longerbeam 	ret = ov5640_init_controls(sensor);
383719a81c14SSteve Longerbeam 	if (ret)
383819a81c14SSteve Longerbeam 		goto entity_cleanup;
383919a81c14SSteve Longerbeam 
384015786f7bSSakari Ailus 	ret = v4l2_async_register_subdev_sensor(&sensor->sd);
384119a81c14SSteve Longerbeam 	if (ret)
384219a81c14SSteve Longerbeam 		goto free_ctrls;
384319a81c14SSteve Longerbeam 
384419a81c14SSteve Longerbeam 	return 0;
384519a81c14SSteve Longerbeam 
384619a81c14SSteve Longerbeam free_ctrls:
384719a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
384819a81c14SSteve Longerbeam entity_cleanup:
384919a81c14SSteve Longerbeam 	media_entity_cleanup(&sensor->sd.entity);
3850bfcba38dSTomi Valkeinen 	mutex_destroy(&sensor->lock);
385119a81c14SSteve Longerbeam 	return ret;
385219a81c14SSteve Longerbeam }
385319a81c14SSteve Longerbeam 
385419a81c14SSteve Longerbeam static int ov5640_remove(struct i2c_client *client)
385519a81c14SSteve Longerbeam {
385619a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
385719a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
385819a81c14SSteve Longerbeam 
385919a81c14SSteve Longerbeam 	v4l2_async_unregister_subdev(&sensor->sd);
386019a81c14SSteve Longerbeam 	media_entity_cleanup(&sensor->sd.entity);
386119a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
3862bfcba38dSTomi Valkeinen 	mutex_destroy(&sensor->lock);
386319a81c14SSteve Longerbeam 
386419a81c14SSteve Longerbeam 	return 0;
386519a81c14SSteve Longerbeam }
386619a81c14SSteve Longerbeam 
386719a81c14SSteve Longerbeam static const struct i2c_device_id ov5640_id[] = {
386819a81c14SSteve Longerbeam 	{"ov5640", 0},
386919a81c14SSteve Longerbeam 	{},
387019a81c14SSteve Longerbeam };
387119a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(i2c, ov5640_id);
387219a81c14SSteve Longerbeam 
387319a81c14SSteve Longerbeam static const struct of_device_id ov5640_dt_ids[] = {
387419a81c14SSteve Longerbeam 	{ .compatible = "ovti,ov5640" },
387519a81c14SSteve Longerbeam 	{ /* sentinel */ }
387619a81c14SSteve Longerbeam };
387719a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(of, ov5640_dt_ids);
387819a81c14SSteve Longerbeam 
387919a81c14SSteve Longerbeam static struct i2c_driver ov5640_i2c_driver = {
388019a81c14SSteve Longerbeam 	.driver = {
388119a81c14SSteve Longerbeam 		.name  = "ov5640",
388219a81c14SSteve Longerbeam 		.of_match_table	= ov5640_dt_ids,
388319a81c14SSteve Longerbeam 	},
388419a81c14SSteve Longerbeam 	.id_table = ov5640_id,
3885e6714993SKieran Bingham 	.probe_new = ov5640_probe,
388619a81c14SSteve Longerbeam 	.remove   = ov5640_remove,
388719a81c14SSteve Longerbeam };
388819a81c14SSteve Longerbeam 
388919a81c14SSteve Longerbeam module_i2c_driver(ov5640_i2c_driver);
389019a81c14SSteve Longerbeam 
389119a81c14SSteve Longerbeam MODULE_DESCRIPTION("OV5640 MIPI Camera Subdev Driver");
389219a81c14SSteve Longerbeam MODULE_LICENSE("GPL");
3893