xref: /openbmc/linux/drivers/media/i2c/ov5640.c (revision ed5c2f5f)
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 
191a89f14bbSJacopo Mondi struct ov5640_pixfmt {
192e3ee691dSHugues Fruchet 	u32 code;
193e3ee691dSHugues Fruchet 	u32 colorspace;
1942d7671f6SJacopo Mondi 	u8 bpp;
195935fbc94SJacopo Mondi 	u8 ctrl00;
196935fbc94SJacopo Mondi 	enum ov5640_format_mux mux;
197a89f14bbSJacopo Mondi };
198a89f14bbSJacopo Mondi 
199a89f14bbSJacopo Mondi static const struct ov5640_pixfmt ov5640_dvp_formats[] = {
2002d7671f6SJacopo Mondi 	{
201935fbc94SJacopo Mondi 		/* YUV422, YUYV */
2022d7671f6SJacopo Mondi 		.code		= MEDIA_BUS_FMT_JPEG_1X8,
2032d7671f6SJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_JPEG,
2042d7671f6SJacopo Mondi 		.bpp		= 16,
205935fbc94SJacopo Mondi 		.ctrl00		= 0x30,
206935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_YUV422,
2072d7671f6SJacopo Mondi 	}, {
208935fbc94SJacopo Mondi 		/* YUV422, UYVY */
2092d7671f6SJacopo Mondi 		.code		= MEDIA_BUS_FMT_UYVY8_2X8,
2102d7671f6SJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
2112d7671f6SJacopo Mondi 		.bpp		= 16,
212935fbc94SJacopo Mondi 		.ctrl00		= 0x3f,
213935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_YUV422,
2142d7671f6SJacopo Mondi 	}, {
215935fbc94SJacopo Mondi 		/* YUV422, YUYV */
2162d7671f6SJacopo Mondi 		.code		= MEDIA_BUS_FMT_YUYV8_2X8,
2172d7671f6SJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
2182d7671f6SJacopo Mondi 		.bpp		= 16,
219935fbc94SJacopo Mondi 		.ctrl00		= 0x30,
220935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_YUV422,
2212d7671f6SJacopo Mondi 	}, {
222935fbc94SJacopo Mondi 		/* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */
2232d7671f6SJacopo Mondi 		.code		= MEDIA_BUS_FMT_RGB565_2X8_LE,
2242d7671f6SJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
2252d7671f6SJacopo Mondi 		.bpp		= 16,
226935fbc94SJacopo Mondi 		.ctrl00		= 0x6f,
227935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_RGB,
2282d7671f6SJacopo Mondi 	}, {
229935fbc94SJacopo Mondi 		/* RGB565 {r[4:0],g[5:3]},{g[2:0],b[4:0]} */
2302d7671f6SJacopo Mondi 		.code		= MEDIA_BUS_FMT_RGB565_2X8_BE,
2312d7671f6SJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
2322d7671f6SJacopo Mondi 		.bpp		= 16,
233935fbc94SJacopo Mondi 		.ctrl00		= 0x61,
234935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_RGB,
2352d7671f6SJacopo Mondi 	}, {
236935fbc94SJacopo Mondi 		/* Raw, BGBG... / GRGR... */
237a89f14bbSJacopo Mondi 		.code		= MEDIA_BUS_FMT_SBGGR8_1X8,
238a89f14bbSJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
239a89f14bbSJacopo Mondi 		.bpp		= 8,
240935fbc94SJacopo Mondi 		.ctrl00		= 0x00,
241935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_RAW_DPC,
242a89f14bbSJacopo Mondi 	}, {
243935fbc94SJacopo Mondi 		/* Raw bayer, GBGB... / RGRG... */
244a89f14bbSJacopo Mondi 		.code		= MEDIA_BUS_FMT_SGBRG8_1X8,
245a89f14bbSJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
246935fbc94SJacopo Mondi 		.bpp		= 8,
247935fbc94SJacopo Mondi 		.ctrl00		= 0x01,
248935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_RAW_DPC,
249a89f14bbSJacopo Mondi 	}, {
250935fbc94SJacopo Mondi 		/* Raw bayer, GRGR... / BGBG... */
251a89f14bbSJacopo Mondi 		.code		= MEDIA_BUS_FMT_SGRBG8_1X8,
252a89f14bbSJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
253a89f14bbSJacopo Mondi 		.bpp		= 8,
254935fbc94SJacopo Mondi 		.ctrl00		= 0x02,
255935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_RAW_DPC,
256a89f14bbSJacopo Mondi 	}, {
257935fbc94SJacopo Mondi 		/* Raw bayer, RGRG... / GBGB... */
258a89f14bbSJacopo Mondi 		.code		= MEDIA_BUS_FMT_SRGGB8_1X8,
259a89f14bbSJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
260a89f14bbSJacopo Mondi 		.bpp		= 8,
261935fbc94SJacopo Mondi 		.ctrl00		= 0x03,
262935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_RAW_DPC,
263a89f14bbSJacopo Mondi 	},
264a89f14bbSJacopo Mondi 	{ /* sentinel */ }
265a89f14bbSJacopo Mondi };
266a89f14bbSJacopo Mondi 
267a89f14bbSJacopo Mondi static const struct ov5640_pixfmt ov5640_csi2_formats[] = {
268a89f14bbSJacopo Mondi 	{
269935fbc94SJacopo Mondi 		/* YUV422, YUYV */
270a89f14bbSJacopo Mondi 		.code		= MEDIA_BUS_FMT_JPEG_1X8,
271a89f14bbSJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_JPEG,
272a89f14bbSJacopo Mondi 		.bpp		= 16,
273935fbc94SJacopo Mondi 		.ctrl00		= 0x30,
274935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_YUV422,
275a89f14bbSJacopo Mondi 	}, {
276935fbc94SJacopo Mondi 		/* YUV422, UYVY */
277a89f14bbSJacopo Mondi 		.code		= MEDIA_BUS_FMT_UYVY8_1X16,
278a89f14bbSJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
279a89f14bbSJacopo Mondi 		.bpp		= 16,
280935fbc94SJacopo Mondi 		.ctrl00		= 0x3f,
281935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_YUV422,
282a89f14bbSJacopo Mondi 	}, {
283935fbc94SJacopo Mondi 		/* YUV422, YUYV */
284a89f14bbSJacopo Mondi 		.code		= MEDIA_BUS_FMT_YUYV8_1X16,
285a89f14bbSJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
286a89f14bbSJacopo Mondi 		.bpp		= 16,
287935fbc94SJacopo Mondi 		.ctrl00		= 0x30,
288935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_YUV422,
289a89f14bbSJacopo Mondi 	}, {
290935fbc94SJacopo Mondi 		/* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */
2910a43fcd7SJacopo Mondi 		.code		= MEDIA_BUS_FMT_RGB565_1X16,
2920a43fcd7SJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
2930a43fcd7SJacopo Mondi 		.bpp		= 16,
294935fbc94SJacopo Mondi 		.ctrl00		= 0x6f,
295935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_RGB,
2960a43fcd7SJacopo Mondi 	}, {
297935fbc94SJacopo Mondi 		/* BGR888: RGB */
2986ac98b41SJacopo Mondi 		.code		= MEDIA_BUS_FMT_BGR888_1X24,
2996ac98b41SJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
3006ac98b41SJacopo Mondi 		.bpp		= 24,
301935fbc94SJacopo Mondi 		.ctrl00		= 0x23,
302935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_RGB,
3036ac98b41SJacopo Mondi 	}, {
304935fbc94SJacopo Mondi 		/* Raw, BGBG... / GRGR... */
3052d7671f6SJacopo Mondi 		.code		= MEDIA_BUS_FMT_SBGGR8_1X8,
3062d7671f6SJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
3072d7671f6SJacopo Mondi 		.bpp		= 8,
308935fbc94SJacopo Mondi 		.ctrl00		= 0x00,
309935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_RAW_DPC,
3102d7671f6SJacopo Mondi 	}, {
311935fbc94SJacopo Mondi 		/* Raw bayer, GBGB... / RGRG... */
3122d7671f6SJacopo Mondi 		.code		= MEDIA_BUS_FMT_SGBRG8_1X8,
3132d7671f6SJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
314935fbc94SJacopo Mondi 		.bpp		= 8,
315935fbc94SJacopo Mondi 		.ctrl00		= 0x01,
316935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_RAW_DPC,
3172d7671f6SJacopo Mondi 	}, {
318935fbc94SJacopo Mondi 		/* Raw bayer, GRGR... / BGBG... */
3192d7671f6SJacopo Mondi 		.code		= MEDIA_BUS_FMT_SGRBG8_1X8,
3202d7671f6SJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
3212d7671f6SJacopo Mondi 		.bpp		= 8,
322935fbc94SJacopo Mondi 		.ctrl00		= 0x02,
323935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_RAW_DPC,
3242d7671f6SJacopo Mondi 	}, {
325935fbc94SJacopo Mondi 		/* Raw bayer, RGRG... / GBGB... */
3262d7671f6SJacopo Mondi 		.code		= MEDIA_BUS_FMT_SRGGB8_1X8,
3272d7671f6SJacopo Mondi 		.colorspace	= V4L2_COLORSPACE_SRGB,
3282d7671f6SJacopo Mondi 		.bpp		= 8,
329935fbc94SJacopo Mondi 		.ctrl00		= 0x03,
330935fbc94SJacopo Mondi 		.mux		= OV5640_FMT_MUX_RAW_DPC,
3312d7671f6SJacopo Mondi 	},
332a89f14bbSJacopo Mondi 	{ /* sentinel */ }
333e3ee691dSHugues Fruchet };
334e3ee691dSHugues Fruchet 
33519a81c14SSteve Longerbeam /*
33619a81c14SSteve Longerbeam  * FIXME: remove this when a subdev API becomes available
33719a81c14SSteve Longerbeam  * to set the MIPI CSI-2 virtual channel.
33819a81c14SSteve Longerbeam  */
33919a81c14SSteve Longerbeam static unsigned int virtual_channel;
3408670d70aSHugues Fruchet module_param(virtual_channel, uint, 0444);
34119a81c14SSteve Longerbeam MODULE_PARM_DESC(virtual_channel,
34219a81c14SSteve Longerbeam 		 "MIPI CSI-2 virtual channel (0..3), default 0");
34319a81c14SSteve Longerbeam 
34419a81c14SSteve Longerbeam static const int ov5640_framerates[] = {
34519a81c14SSteve Longerbeam 	[OV5640_15_FPS] = 15,
34619a81c14SSteve Longerbeam 	[OV5640_30_FPS] = 30,
347e823fb16SMaxime Ripard 	[OV5640_60_FPS] = 60,
34819a81c14SSteve Longerbeam };
34919a81c14SSteve Longerbeam 
35019a81c14SSteve Longerbeam /* regulator supplies */
35119a81c14SSteve Longerbeam static const char * const ov5640_supply_name[] = {
35241d8d7f5SHugues Fruchet 	"DOVDD", /* Digital I/O (1.8V) supply */
35319a81c14SSteve Longerbeam 	"AVDD",  /* Analog (2.8V) supply */
35424c8ac89SFabio Estevam 	"DVDD",  /* Digital Core (1.5V) supply */
35519a81c14SSteve Longerbeam };
35619a81c14SSteve Longerbeam 
35719a81c14SSteve Longerbeam #define OV5640_NUM_SUPPLIES ARRAY_SIZE(ov5640_supply_name)
35819a81c14SSteve Longerbeam 
35919a81c14SSteve Longerbeam /*
36019a81c14SSteve Longerbeam  * Image size under 1280 * 960 are SUBSAMPLING
36119a81c14SSteve Longerbeam  * Image size upper 1280 * 960 are SCALING
36219a81c14SSteve Longerbeam  */
36319a81c14SSteve Longerbeam enum ov5640_downsize_mode {
36419a81c14SSteve Longerbeam 	SUBSAMPLING,
36519a81c14SSteve Longerbeam 	SCALING,
36619a81c14SSteve Longerbeam };
36719a81c14SSteve Longerbeam 
36819a81c14SSteve Longerbeam struct reg_value {
36919a81c14SSteve Longerbeam 	u16 reg_addr;
37019a81c14SSteve Longerbeam 	u8 val;
37119a81c14SSteve Longerbeam 	u8 mask;
37219a81c14SSteve Longerbeam 	u32 delay_ms;
37319a81c14SSteve Longerbeam };
37419a81c14SSteve Longerbeam 
3755113d5b3SJacopo Mondi struct ov5640_timings {
3763145efcdSJacopo Mondi 	/* Analog crop rectangle. */
3773145efcdSJacopo Mondi 	struct v4l2_rect analog_crop;
3783145efcdSJacopo Mondi 	/* Visibile crop: from analog crop top-left corner. */
3793145efcdSJacopo Mondi 	struct v4l2_rect crop;
3805113d5b3SJacopo Mondi 	/* Total pixels per line: width + fixed hblank. */
381476dec01SMaxime Ripard 	u32 htot;
3825113d5b3SJacopo Mondi 	/* Default vertical blanking: frame height = height + vblank. */
3833145efcdSJacopo Mondi 	u32 vblank_def;
3845113d5b3SJacopo Mondi };
3855113d5b3SJacopo Mondi 
3865113d5b3SJacopo Mondi struct ov5640_mode_info {
3875113d5b3SJacopo Mondi 	enum ov5640_mode_id id;
3885113d5b3SJacopo Mondi 	enum ov5640_downsize_mode dn_mode;
3895113d5b3SJacopo Mondi 	enum ov5640_pixel_rate_id pixel_rate;
3905113d5b3SJacopo Mondi 
3915113d5b3SJacopo Mondi 	unsigned int width;
3925113d5b3SJacopo Mondi 	unsigned int height;
3935113d5b3SJacopo Mondi 
3945113d5b3SJacopo Mondi 	struct ov5640_timings dvp_timings;
3955113d5b3SJacopo Mondi 	struct ov5640_timings csi2_timings;
3965113d5b3SJacopo Mondi 
39719a81c14SSteve Longerbeam 	const struct reg_value *reg_data;
39819a81c14SSteve Longerbeam 	u32 reg_data_size;
3995113d5b3SJacopo Mondi 
4005113d5b3SJacopo Mondi 	/* Used by s_frame_interval only. */
4015554c80eSAdam Ford 	u32 max_fps;
40219f2e3e6SHugues Fruchet 	u32 def_fps;
40319a81c14SSteve Longerbeam };
40419a81c14SSteve Longerbeam 
40519a81c14SSteve Longerbeam struct ov5640_ctrls {
40619a81c14SSteve Longerbeam 	struct v4l2_ctrl_handler handler;
407cc196e48SBenoit Parrot 	struct v4l2_ctrl *pixel_rate;
4087a3b8d4bSJacopo Mondi 	struct v4l2_ctrl *link_freq;
40932979f67SJacopo Mondi 	struct v4l2_ctrl *hblank;
410bce93b82SJacopo Mondi 	struct v4l2_ctrl *vblank;
41119a81c14SSteve Longerbeam 	struct {
41219a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_exp;
41319a81c14SSteve Longerbeam 		struct v4l2_ctrl *exposure;
41419a81c14SSteve Longerbeam 	};
41519a81c14SSteve Longerbeam 	struct {
41619a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_wb;
41719a81c14SSteve Longerbeam 		struct v4l2_ctrl *blue_balance;
41819a81c14SSteve Longerbeam 		struct v4l2_ctrl *red_balance;
41919a81c14SSteve Longerbeam 	};
42019a81c14SSteve Longerbeam 	struct {
42119a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_gain;
42219a81c14SSteve Longerbeam 		struct v4l2_ctrl *gain;
42319a81c14SSteve Longerbeam 	};
42419a81c14SSteve Longerbeam 	struct v4l2_ctrl *brightness;
4251068fecaSMylène Josserand 	struct v4l2_ctrl *light_freq;
42619a81c14SSteve Longerbeam 	struct v4l2_ctrl *saturation;
42719a81c14SSteve Longerbeam 	struct v4l2_ctrl *contrast;
42819a81c14SSteve Longerbeam 	struct v4l2_ctrl *hue;
42919a81c14SSteve Longerbeam 	struct v4l2_ctrl *test_pattern;
430ce85705aSHugues Fruchet 	struct v4l2_ctrl *hflip;
431ce85705aSHugues Fruchet 	struct v4l2_ctrl *vflip;
43219a81c14SSteve Longerbeam };
43319a81c14SSteve Longerbeam 
43419a81c14SSteve Longerbeam struct ov5640_dev {
43519a81c14SSteve Longerbeam 	struct i2c_client *i2c_client;
43619a81c14SSteve Longerbeam 	struct v4l2_subdev sd;
43719a81c14SSteve Longerbeam 	struct media_pad pad;
43819a81c14SSteve Longerbeam 	struct v4l2_fwnode_endpoint ep; /* the parsed DT endpoint info */
43919a81c14SSteve Longerbeam 	struct clk *xclk; /* system clock to OV5640 */
44019a81c14SSteve Longerbeam 	u32 xclk_freq;
44119a81c14SSteve Longerbeam 
44219a81c14SSteve Longerbeam 	struct regulator_bulk_data supplies[OV5640_NUM_SUPPLIES];
44319a81c14SSteve Longerbeam 	struct gpio_desc *reset_gpio;
44419a81c14SSteve Longerbeam 	struct gpio_desc *pwdn_gpio;
445c3f3ba3eSHugues Fruchet 	bool   upside_down;
44619a81c14SSteve Longerbeam 
44719a81c14SSteve Longerbeam 	/* lock to protect all members below */
44819a81c14SSteve Longerbeam 	struct mutex lock;
44919a81c14SSteve Longerbeam 
45019a81c14SSteve Longerbeam 	int power_count;
45119a81c14SSteve Longerbeam 
45219a81c14SSteve Longerbeam 	struct v4l2_mbus_framefmt fmt;
453fb98e29fSHugues Fruchet 	bool pending_fmt_change;
45419a81c14SSteve Longerbeam 
45519a81c14SSteve Longerbeam 	const struct ov5640_mode_info *current_mode;
456985cdcb0SHugues Fruchet 	const struct ov5640_mode_info *last_mode;
45719a81c14SSteve Longerbeam 	enum ov5640_frame_rate current_fr;
45819a81c14SSteve Longerbeam 	struct v4l2_fract frame_interval;
4593c28588fSJacopo Mondi 	s64 current_link_freq;
46019a81c14SSteve Longerbeam 
46119a81c14SSteve Longerbeam 	struct ov5640_ctrls ctrls;
46219a81c14SSteve Longerbeam 
46319a81c14SSteve Longerbeam 	u32 prev_sysclk, prev_hts;
46419a81c14SSteve Longerbeam 	u32 ae_low, ae_high, ae_target;
46519a81c14SSteve Longerbeam 
46619a81c14SSteve Longerbeam 	bool pending_mode_change;
46719a81c14SSteve Longerbeam 	bool streaming;
46819a81c14SSteve Longerbeam };
46919a81c14SSteve Longerbeam 
47019a81c14SSteve Longerbeam static inline struct ov5640_dev *to_ov5640_dev(struct v4l2_subdev *sd)
47119a81c14SSteve Longerbeam {
47219a81c14SSteve Longerbeam 	return container_of(sd, struct ov5640_dev, sd);
47319a81c14SSteve Longerbeam }
47419a81c14SSteve Longerbeam 
47519a81c14SSteve Longerbeam static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
47619a81c14SSteve Longerbeam {
47719a81c14SSteve Longerbeam 	return &container_of(ctrl->handler, struct ov5640_dev,
47819a81c14SSteve Longerbeam 			     ctrls.handler)->sd;
47919a81c14SSteve Longerbeam }
48019a81c14SSteve Longerbeam 
4818e823f5cSJacopo Mondi static inline bool ov5640_is_csi2(const struct ov5640_dev *sensor)
4828e823f5cSJacopo Mondi {
4838e823f5cSJacopo Mondi 	return sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY;
4848e823f5cSJacopo Mondi }
4858e823f5cSJacopo Mondi 
486a89f14bbSJacopo Mondi static inline const struct ov5640_pixfmt *
487a89f14bbSJacopo Mondi ov5640_formats(struct ov5640_dev *sensor)
488a89f14bbSJacopo Mondi {
489a89f14bbSJacopo Mondi 	return ov5640_is_csi2(sensor) ? ov5640_csi2_formats
490a89f14bbSJacopo Mondi 				      : ov5640_dvp_formats;
491a89f14bbSJacopo Mondi }
492a89f14bbSJacopo Mondi 
493a89f14bbSJacopo Mondi static const struct ov5640_pixfmt *
494a89f14bbSJacopo Mondi ov5640_code_to_pixfmt(struct ov5640_dev *sensor, u32 code)
495a89f14bbSJacopo Mondi {
496a89f14bbSJacopo Mondi 	const struct ov5640_pixfmt *formats = ov5640_formats(sensor);
497a89f14bbSJacopo Mondi 	unsigned int i;
498a89f14bbSJacopo Mondi 
499a89f14bbSJacopo Mondi 	for (i = 0; formats[i].code; ++i) {
500a89f14bbSJacopo Mondi 		if (formats[i].code == code)
501a89f14bbSJacopo Mondi 			return &formats[i];
502a89f14bbSJacopo Mondi 	}
503a89f14bbSJacopo Mondi 
504a89f14bbSJacopo Mondi 	return &formats[0];
505a89f14bbSJacopo Mondi }
506a89f14bbSJacopo Mondi 
507a89f14bbSJacopo Mondi static u32 ov5640_code_to_bpp(struct ov5640_dev *sensor, u32 code)
508a89f14bbSJacopo Mondi {
509a89f14bbSJacopo Mondi 	const struct ov5640_pixfmt *format = ov5640_code_to_pixfmt(sensor,
510a89f14bbSJacopo Mondi 								   code);
511a89f14bbSJacopo Mondi 
512a89f14bbSJacopo Mondi 	return format->bpp;
513a89f14bbSJacopo Mondi }
514a89f14bbSJacopo Mondi 
51519a81c14SSteve Longerbeam /*
51619a81c14SSteve Longerbeam  * FIXME: all of these register tables are likely filled with
51719a81c14SSteve Longerbeam  * entries that set the register to their power-on default values,
51819a81c14SSteve Longerbeam  * and which are otherwise not touched by this driver. Those entries
51919a81c14SSteve Longerbeam  * should be identified and removed to speed register load time
52019a81c14SSteve Longerbeam  * over i2c.
52119a81c14SSteve Longerbeam  */
522fb98e29fSHugues Fruchet /* YUV422 UYVY VGA@30fps */
52390b0f355SJacopo Mondi 
52490b0f355SJacopo Mondi static const struct v4l2_mbus_framefmt ov5640_default_fmt = {
52590b0f355SJacopo Mondi 	.code = MEDIA_BUS_FMT_UYVY8_2X8,
52690b0f355SJacopo Mondi 	.width = 640,
52790b0f355SJacopo Mondi 	.height = 480,
52890b0f355SJacopo Mondi 	.colorspace = V4L2_COLORSPACE_SRGB,
52990b0f355SJacopo Mondi 	.ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SRGB),
53090b0f355SJacopo Mondi 	.quantization = V4L2_QUANTIZATION_FULL_RANGE,
53190b0f355SJacopo Mondi 	.xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SRGB),
53290b0f355SJacopo Mondi 	.field = V4L2_FIELD_NONE,
53390b0f355SJacopo Mondi };
53490b0f355SJacopo Mondi 
535e4359019SJacopo Mondi static const struct reg_value ov5640_init_setting[] = {
53619a81c14SSteve Longerbeam 	{0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0},
537576f5d4bSLad Prabhakar 	{0x3103, 0x03, 0, 0}, {0x3630, 0x36, 0, 0},
53819a81c14SSteve Longerbeam 	{0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0},
53919a81c14SSteve Longerbeam 	{0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0},
54019a81c14SSteve Longerbeam 	{0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0},
54119a81c14SSteve Longerbeam 	{0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, {0x3906, 0x10, 0, 0},
54219a81c14SSteve Longerbeam 	{0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, {0x3600, 0x08, 0, 0},
54319a81c14SSteve Longerbeam 	{0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, {0x3620, 0x52, 0, 0},
54419a81c14SSteve Longerbeam 	{0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, {0x3a13, 0x43, 0, 0},
54519a81c14SSteve Longerbeam 	{0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3635, 0x13, 0, 0},
54619a81c14SSteve Longerbeam 	{0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, {0x3622, 0x01, 0, 0},
54719a81c14SSteve Longerbeam 	{0x3c01, 0xa4, 0, 0}, {0x3c04, 0x28, 0, 0}, {0x3c05, 0x98, 0, 0},
54819a81c14SSteve Longerbeam 	{0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0},
54919a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
55019a81c14SSteve Longerbeam 	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
5513145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
55219a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
55319a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
55419a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
55519a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
55619a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
55719a81c14SSteve Longerbeam 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0},
55819a81c14SSteve Longerbeam 	{0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0},
559aa4bb8b8SJacopo Mondi 	{0x302e, 0x08, 0, 0}, {0x4300, 0x3f, 0, 0},
5602b5c18f9SChen-Yu Tsai 	{0x501f, 0x00, 0, 0}, {0x4407, 0x04, 0, 0},
56119a81c14SSteve Longerbeam 	{0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
562aa4bb8b8SJacopo Mondi 	{0x4837, 0x0a, 0, 0}, {0x3824, 0x02, 0, 0},
56319a81c14SSteve Longerbeam 	{0x5000, 0xa7, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0},
56419a81c14SSteve Longerbeam 	{0x5181, 0xf2, 0, 0}, {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0},
56519a81c14SSteve Longerbeam 	{0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0},
56619a81c14SSteve Longerbeam 	{0x5187, 0x09, 0, 0}, {0x5188, 0x09, 0, 0}, {0x5189, 0x88, 0, 0},
56719a81c14SSteve Longerbeam 	{0x518a, 0x54, 0, 0}, {0x518b, 0xee, 0, 0}, {0x518c, 0xb2, 0, 0},
56819a81c14SSteve Longerbeam 	{0x518d, 0x50, 0, 0}, {0x518e, 0x34, 0, 0}, {0x518f, 0x6b, 0, 0},
56919a81c14SSteve Longerbeam 	{0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0},
57019a81c14SSteve Longerbeam 	{0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0},
57119a81c14SSteve Longerbeam 	{0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0},
57219a81c14SSteve Longerbeam 	{0x5199, 0x6c, 0, 0}, {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0},
57319a81c14SSteve Longerbeam 	{0x519c, 0x09, 0, 0}, {0x519d, 0x2b, 0, 0}, {0x519e, 0x38, 0, 0},
57419a81c14SSteve Longerbeam 	{0x5381, 0x1e, 0, 0}, {0x5382, 0x5b, 0, 0}, {0x5383, 0x08, 0, 0},
57519a81c14SSteve Longerbeam 	{0x5384, 0x0a, 0, 0}, {0x5385, 0x7e, 0, 0}, {0x5386, 0x88, 0, 0},
57619a81c14SSteve Longerbeam 	{0x5387, 0x7c, 0, 0}, {0x5388, 0x6c, 0, 0}, {0x5389, 0x10, 0, 0},
57719a81c14SSteve Longerbeam 	{0x538a, 0x01, 0, 0}, {0x538b, 0x98, 0, 0}, {0x5300, 0x08, 0, 0},
57819a81c14SSteve Longerbeam 	{0x5301, 0x30, 0, 0}, {0x5302, 0x10, 0, 0}, {0x5303, 0x00, 0, 0},
57919a81c14SSteve Longerbeam 	{0x5304, 0x08, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x08, 0, 0},
58019a81c14SSteve Longerbeam 	{0x5307, 0x16, 0, 0}, {0x5309, 0x08, 0, 0}, {0x530a, 0x30, 0, 0},
58119a81c14SSteve Longerbeam 	{0x530b, 0x04, 0, 0}, {0x530c, 0x06, 0, 0}, {0x5480, 0x01, 0, 0},
58219a81c14SSteve Longerbeam 	{0x5481, 0x08, 0, 0}, {0x5482, 0x14, 0, 0}, {0x5483, 0x28, 0, 0},
58319a81c14SSteve Longerbeam 	{0x5484, 0x51, 0, 0}, {0x5485, 0x65, 0, 0}, {0x5486, 0x71, 0, 0},
58419a81c14SSteve Longerbeam 	{0x5487, 0x7d, 0, 0}, {0x5488, 0x87, 0, 0}, {0x5489, 0x91, 0, 0},
58519a81c14SSteve Longerbeam 	{0x548a, 0x9a, 0, 0}, {0x548b, 0xaa, 0, 0}, {0x548c, 0xb8, 0, 0},
58619a81c14SSteve Longerbeam 	{0x548d, 0xcd, 0, 0}, {0x548e, 0xdd, 0, 0}, {0x548f, 0xea, 0, 0},
58719a81c14SSteve Longerbeam 	{0x5490, 0x1d, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5583, 0x40, 0, 0},
58819a81c14SSteve Longerbeam 	{0x5584, 0x10, 0, 0}, {0x5589, 0x10, 0, 0}, {0x558a, 0x00, 0, 0},
58919a81c14SSteve Longerbeam 	{0x558b, 0xf8, 0, 0}, {0x5800, 0x23, 0, 0}, {0x5801, 0x14, 0, 0},
59019a81c14SSteve Longerbeam 	{0x5802, 0x0f, 0, 0}, {0x5803, 0x0f, 0, 0}, {0x5804, 0x12, 0, 0},
59119a81c14SSteve Longerbeam 	{0x5805, 0x26, 0, 0}, {0x5806, 0x0c, 0, 0}, {0x5807, 0x08, 0, 0},
59219a81c14SSteve Longerbeam 	{0x5808, 0x05, 0, 0}, {0x5809, 0x05, 0, 0}, {0x580a, 0x08, 0, 0},
59319a81c14SSteve Longerbeam 	{0x580b, 0x0d, 0, 0}, {0x580c, 0x08, 0, 0}, {0x580d, 0x03, 0, 0},
59419a81c14SSteve Longerbeam 	{0x580e, 0x00, 0, 0}, {0x580f, 0x00, 0, 0}, {0x5810, 0x03, 0, 0},
59519a81c14SSteve Longerbeam 	{0x5811, 0x09, 0, 0}, {0x5812, 0x07, 0, 0}, {0x5813, 0x03, 0, 0},
59619a81c14SSteve Longerbeam 	{0x5814, 0x00, 0, 0}, {0x5815, 0x01, 0, 0}, {0x5816, 0x03, 0, 0},
59719a81c14SSteve Longerbeam 	{0x5817, 0x08, 0, 0}, {0x5818, 0x0d, 0, 0}, {0x5819, 0x08, 0, 0},
59819a81c14SSteve Longerbeam 	{0x581a, 0x05, 0, 0}, {0x581b, 0x06, 0, 0}, {0x581c, 0x08, 0, 0},
59919a81c14SSteve Longerbeam 	{0x581d, 0x0e, 0, 0}, {0x581e, 0x29, 0, 0}, {0x581f, 0x17, 0, 0},
60019a81c14SSteve Longerbeam 	{0x5820, 0x11, 0, 0}, {0x5821, 0x11, 0, 0}, {0x5822, 0x15, 0, 0},
60119a81c14SSteve Longerbeam 	{0x5823, 0x28, 0, 0}, {0x5824, 0x46, 0, 0}, {0x5825, 0x26, 0, 0},
60219a81c14SSteve Longerbeam 	{0x5826, 0x08, 0, 0}, {0x5827, 0x26, 0, 0}, {0x5828, 0x64, 0, 0},
60319a81c14SSteve Longerbeam 	{0x5829, 0x26, 0, 0}, {0x582a, 0x24, 0, 0}, {0x582b, 0x22, 0, 0},
60419a81c14SSteve Longerbeam 	{0x582c, 0x24, 0, 0}, {0x582d, 0x24, 0, 0}, {0x582e, 0x06, 0, 0},
60519a81c14SSteve Longerbeam 	{0x582f, 0x22, 0, 0}, {0x5830, 0x40, 0, 0}, {0x5831, 0x42, 0, 0},
60619a81c14SSteve Longerbeam 	{0x5832, 0x24, 0, 0}, {0x5833, 0x26, 0, 0}, {0x5834, 0x24, 0, 0},
60719a81c14SSteve Longerbeam 	{0x5835, 0x22, 0, 0}, {0x5836, 0x22, 0, 0}, {0x5837, 0x26, 0, 0},
60819a81c14SSteve Longerbeam 	{0x5838, 0x44, 0, 0}, {0x5839, 0x24, 0, 0}, {0x583a, 0x26, 0, 0},
60919a81c14SSteve Longerbeam 	{0x583b, 0x28, 0, 0}, {0x583c, 0x42, 0, 0}, {0x583d, 0xce, 0, 0},
61019a81c14SSteve Longerbeam 	{0x5025, 0x00, 0, 0}, {0x3a0f, 0x30, 0, 0}, {0x3a10, 0x28, 0, 0},
61119a81c14SSteve Longerbeam 	{0x3a1b, 0x30, 0, 0}, {0x3a1e, 0x26, 0, 0}, {0x3a11, 0x60, 0, 0},
61219a81c14SSteve Longerbeam 	{0x3a1f, 0x14, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3c00, 0x04, 0, 300},
61319a81c14SSteve Longerbeam };
61419a81c14SSteve Longerbeam 
615db15c195SJacopo Mondi static const struct reg_value ov5640_setting_low_res[] = {
616c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
61719a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
618ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
6193145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
62019a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
62119a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
62219a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
62319a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
62419a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
6252b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
626e15197bdSJacopo Mondi 	{0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0},
62719a81c14SSteve Longerbeam };
62819a81c14SSteve Longerbeam 
629086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_720P_1280_720[] = {
630c14d107eSMaxime Ripard 	{0x3c07, 0x07, 0, 0},
63119a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
632ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
6333145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
63419a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
63519a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0},
63619a81c14SSteve Longerbeam 	{0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0},
63719a81c14SSteve Longerbeam 	{0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0},
63819a81c14SSteve Longerbeam 	{0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0},
6392b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
64019a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
64119a81c14SSteve Longerbeam 	{0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0},
64219a81c14SSteve Longerbeam };
64319a81c14SSteve Longerbeam 
644086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_1080P_1920_1080[] = {
645c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
64619a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
647ce85705aSHugues Fruchet 	{0x3814, 0x11, 0, 0},
6483145efcdSJacopo Mondi 	{0x3815, 0x11, 0, 0},
64919a81c14SSteve Longerbeam 	{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
65019a81c14SSteve Longerbeam 	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
65119a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
65219a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
65319a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
6542b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0},
65519a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
656c14d107eSMaxime Ripard 	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0},
657c14d107eSMaxime Ripard 	{0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0},
65819a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
659476dec01SMaxime Ripard 	{0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0},
66019a81c14SSteve Longerbeam 	{0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0},
66119a81c14SSteve Longerbeam 	{0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0},
66219a81c14SSteve Longerbeam 	{0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0},
6632b5c18f9SChen-Yu Tsai 	{0x3a15, 0x60, 0, 0}, {0x4407, 0x04, 0, 0},
66419a81c14SSteve Longerbeam 	{0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0},
66592b9096cSBenoit Parrot 	{0x4005, 0x1a, 0, 0},
66619a81c14SSteve Longerbeam };
66719a81c14SSteve Longerbeam 
668086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_QSXGA_2592_1944[] = {
669c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
67019a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
671ce85705aSHugues Fruchet 	{0x3814, 0x11, 0, 0},
6723145efcdSJacopo Mondi 	{0x3815, 0x11, 0, 0},
67319a81c14SSteve Longerbeam 	{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
67419a81c14SSteve Longerbeam 	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
67519a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
67619a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
67719a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
6782b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0},
67919a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
68019a81c14SSteve Longerbeam 	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70},
68119a81c14SSteve Longerbeam };
68219a81c14SSteve Longerbeam 
6835113d5b3SJacopo Mondi static const struct ov5640_mode_info ov5640_mode_data[OV5640_NUM_MODES] = {
6848409d017SJacopo Mondi 	{
6858409d017SJacopo Mondi 		/* 160x120 */
6863145efcdSJacopo Mondi 		.id		= OV5640_MODE_QQVGA_160_120,
6873145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
6883145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
6895113d5b3SJacopo Mondi 		.width		= 160,
6905113d5b3SJacopo Mondi 		.height		= 120,
6915113d5b3SJacopo Mondi 		.dvp_timings = {
6923145efcdSJacopo Mondi 			.analog_crop = {
6933145efcdSJacopo Mondi 				.left	= 0,
6943145efcdSJacopo Mondi 				.top	= 4,
6953145efcdSJacopo Mondi 				.width	= 2624,
6963145efcdSJacopo Mondi 				.height	= 1944,
6973145efcdSJacopo Mondi 			},
6983145efcdSJacopo Mondi 			.crop = {
6993145efcdSJacopo Mondi 				.left	= 16,
7003145efcdSJacopo Mondi 				.top	= 6,
7013145efcdSJacopo Mondi 				.width	= 160,
7023145efcdSJacopo Mondi 				.height	= 120,
7033145efcdSJacopo Mondi 			},
7043145efcdSJacopo Mondi 			.htot		= 1896,
7053145efcdSJacopo Mondi 			.vblank_def	= 864,
7065113d5b3SJacopo Mondi 		},
7075113d5b3SJacopo Mondi 		.csi2_timings = {
7085113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
7095113d5b3SJacopo Mondi 			.analog_crop = {
7105113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
7115113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
7125113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
7135113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
7145113d5b3SJacopo Mondi 			},
7155113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
7165113d5b3SJacopo Mondi 			.crop = {
7175113d5b3SJacopo Mondi 				.left	= 2,
7185113d5b3SJacopo Mondi 				.top	= 4,
7195113d5b3SJacopo Mondi 				.width	= 160,
7205113d5b3SJacopo Mondi 				.height	= 120,
7215113d5b3SJacopo Mondi 			},
722961bed9fSJacopo Mondi 			.htot		= 1600,
723961bed9fSJacopo Mondi 			.vblank_def	= 878,
7245113d5b3SJacopo Mondi 		},
725db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
726db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
72719f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
72819f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
7298409d017SJacopo Mondi 	}, {
7308409d017SJacopo Mondi 		/* 176x144 */
7313145efcdSJacopo Mondi 		.id		= OV5640_MODE_QCIF_176_144,
7323145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
7333145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
7345113d5b3SJacopo Mondi 		.width		= 176,
7355113d5b3SJacopo Mondi 		.height		= 144,
7365113d5b3SJacopo Mondi 		.dvp_timings = {
7373145efcdSJacopo Mondi 			.analog_crop = {
7383145efcdSJacopo Mondi 				.left	= 0,
7393145efcdSJacopo Mondi 				.top	= 4,
7403145efcdSJacopo Mondi 				.width	= 2624,
7413145efcdSJacopo Mondi 				.height	= 1944,
7423145efcdSJacopo Mondi 			},
7433145efcdSJacopo Mondi 			.crop = {
7443145efcdSJacopo Mondi 				.left	= 16,
7453145efcdSJacopo Mondi 				.top	= 6,
7463145efcdSJacopo Mondi 				.width	= 176,
7473145efcdSJacopo Mondi 				.height	= 144,
7483145efcdSJacopo Mondi 			},
7493145efcdSJacopo Mondi 			.htot		= 1896,
7503145efcdSJacopo Mondi 			.vblank_def	= 840,
7515113d5b3SJacopo Mondi 		},
7525113d5b3SJacopo Mondi 		.csi2_timings = {
7535113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
7545113d5b3SJacopo Mondi 			.analog_crop = {
7555113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
7565113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
7575113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
7585113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
7595113d5b3SJacopo Mondi 			},
7605113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
7615113d5b3SJacopo Mondi 			.crop = {
7625113d5b3SJacopo Mondi 				.left	= 2,
7635113d5b3SJacopo Mondi 				.top	= 4,
7645113d5b3SJacopo Mondi 				.width	= 176,
7655113d5b3SJacopo Mondi 				.height	= 144,
7665113d5b3SJacopo Mondi 			},
767961bed9fSJacopo Mondi 			.htot		= 1600,
768961bed9fSJacopo Mondi 			.vblank_def	= 854,
7695113d5b3SJacopo Mondi 		},
770db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
771db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
77219f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
77319f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
7748409d017SJacopo Mondi 	}, {
7758409d017SJacopo Mondi 		/* 320x240 */
7763145efcdSJacopo Mondi 		.id		= OV5640_MODE_QVGA_320_240,
7773145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
7785113d5b3SJacopo Mondi 		.width		= 320,
7795113d5b3SJacopo Mondi 		.height		= 240,
7803145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
7815113d5b3SJacopo Mondi 		.dvp_timings = {
7823145efcdSJacopo Mondi 			.analog_crop = {
7833145efcdSJacopo Mondi 				.left	= 0,
7843145efcdSJacopo Mondi 				.top	= 4,
7853145efcdSJacopo Mondi 				.width	= 2624,
7863145efcdSJacopo Mondi 				.height	= 1944,
7873145efcdSJacopo Mondi 			},
7883145efcdSJacopo Mondi 			.crop = {
7893145efcdSJacopo Mondi 				.left	= 16,
7903145efcdSJacopo Mondi 				.top	= 6,
7913145efcdSJacopo Mondi 				.width	= 320,
7923145efcdSJacopo Mondi 				.height	= 240,
7933145efcdSJacopo Mondi 			},
7943145efcdSJacopo Mondi 			.htot		= 1896,
7953145efcdSJacopo Mondi 			.vblank_def	= 744,
7965113d5b3SJacopo Mondi 		},
7975113d5b3SJacopo Mondi 		.csi2_timings = {
7985113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
7995113d5b3SJacopo Mondi 			.analog_crop = {
8005113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
8015113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
8025113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
8035113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
8045113d5b3SJacopo Mondi 			},
8055113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
8065113d5b3SJacopo Mondi 			.crop = {
8075113d5b3SJacopo Mondi 				.left	= 2,
8085113d5b3SJacopo Mondi 				.top	= 4,
8095113d5b3SJacopo Mondi 				.width	= 320,
8105113d5b3SJacopo Mondi 				.height	= 240,
8115113d5b3SJacopo Mondi 			},
812961bed9fSJacopo Mondi 			.htot		= 1600,
813961bed9fSJacopo Mondi 			.vblank_def	= 760,
8145113d5b3SJacopo Mondi 		},
815db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
816db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
81719f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
81819f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
8198409d017SJacopo Mondi 	}, {
8208409d017SJacopo Mondi 		/* 640x480 */
8213145efcdSJacopo Mondi 		.id		= OV5640_MODE_VGA_640_480,
8223145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
8233145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
8245113d5b3SJacopo Mondi 		.width		= 640,
8255113d5b3SJacopo Mondi 		.height		= 480,
8265113d5b3SJacopo Mondi 		.dvp_timings = {
8273145efcdSJacopo Mondi 			.analog_crop = {
8283145efcdSJacopo Mondi 				.left	= 0,
8293145efcdSJacopo Mondi 				.top	= 4,
8303145efcdSJacopo Mondi 				.width	= 2624,
8313145efcdSJacopo Mondi 				.height	= 1944,
8323145efcdSJacopo Mondi 			},
8333145efcdSJacopo Mondi 			.crop = {
8343145efcdSJacopo Mondi 				.left	= 16,
8353145efcdSJacopo Mondi 				.top	= 6,
8363145efcdSJacopo Mondi 				.width	= 640,
8373145efcdSJacopo Mondi 				.height	= 480,
8383145efcdSJacopo Mondi 			},
8393145efcdSJacopo Mondi 			.htot		= 1896,
8403145efcdSJacopo Mondi 			.vblank_def	= 600,
8415113d5b3SJacopo Mondi 		},
8425113d5b3SJacopo Mondi 		.csi2_timings = {
8435113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
8445113d5b3SJacopo Mondi 			.analog_crop = {
8455113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
8465113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
8475113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
8485113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
8495113d5b3SJacopo Mondi 			},
8505113d5b3SJacopo Mondi 			/* Maintain a minimum processing margin. */
8515113d5b3SJacopo Mondi 			.crop = {
8525113d5b3SJacopo Mondi 				.left	= 2,
8535113d5b3SJacopo Mondi 				.top	= 4,
8545113d5b3SJacopo Mondi 				.width	= 640,
8555113d5b3SJacopo Mondi 				.height	= 480,
8565113d5b3SJacopo Mondi 			},
857961bed9fSJacopo Mondi 			.htot		= 1600,
858961bed9fSJacopo Mondi 			.vblank_def	= 520,
8595113d5b3SJacopo Mondi 		},
860db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
861db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
86219f2e3e6SHugues Fruchet 		.max_fps	= OV5640_60_FPS,
86319f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
8648409d017SJacopo Mondi 	}, {
8658409d017SJacopo Mondi 		/* 720x480 */
8663145efcdSJacopo Mondi 		.id		= OV5640_MODE_NTSC_720_480,
8673145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
8685113d5b3SJacopo Mondi 		.width		= 720,
8695113d5b3SJacopo Mondi 		.height		= 480,
8703145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
8715113d5b3SJacopo Mondi 		.dvp_timings = {
8723145efcdSJacopo Mondi 			.analog_crop = {
8733145efcdSJacopo Mondi 				.left	= 0,
8743145efcdSJacopo Mondi 				.top	= 4,
8753145efcdSJacopo Mondi 				.width	= 2624,
8763145efcdSJacopo Mondi 				.height	= 1944,
8773145efcdSJacopo Mondi 			},
8783145efcdSJacopo Mondi 			.crop = {
879e74ef55bSJacopo Mondi 				.left	= 56,
8803145efcdSJacopo Mondi 				.top	= 60,
8813145efcdSJacopo Mondi 				.width	= 720,
8823145efcdSJacopo Mondi 				.height	= 480,
8833145efcdSJacopo Mondi 			},
8843145efcdSJacopo Mondi 			.htot		= 1896,
8853145efcdSJacopo Mondi 			.vblank_def	= 504,
8865113d5b3SJacopo Mondi 		},
8875113d5b3SJacopo Mondi 		.csi2_timings = {
8885113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
8895113d5b3SJacopo Mondi 			.analog_crop = {
8905113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
8915113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
8925113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
8935113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
8945113d5b3SJacopo Mondi 			},
8955113d5b3SJacopo Mondi 			.crop = {
8965113d5b3SJacopo Mondi 				.left	= 56,
8975113d5b3SJacopo Mondi 				.top	= 60,
8985113d5b3SJacopo Mondi 				.width	= 720,
8995113d5b3SJacopo Mondi 				.height	= 480,
9005113d5b3SJacopo Mondi 			},
9015113d5b3SJacopo Mondi 			.htot		= 1896,
902961bed9fSJacopo Mondi 			.vblank_def	= 1206,
9035113d5b3SJacopo Mondi 		},
904db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
905db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
90619f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
90719f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
9088409d017SJacopo Mondi 	}, {
9098409d017SJacopo Mondi 		/* 720x576 */
9103145efcdSJacopo Mondi 		.id		= OV5640_MODE_PAL_720_576,
9113145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
9125113d5b3SJacopo Mondi 		.width		= 720,
9135113d5b3SJacopo Mondi 		.height		= 576,
9143145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
9155113d5b3SJacopo Mondi 		.dvp_timings = {
9163145efcdSJacopo Mondi 			.analog_crop = {
9173145efcdSJacopo Mondi 				.left	= 0,
9183145efcdSJacopo Mondi 				.top	= 4,
9193145efcdSJacopo Mondi 				.width	= 2624,
9203145efcdSJacopo Mondi 				.height	= 1944,
9213145efcdSJacopo Mondi 			},
9223145efcdSJacopo Mondi 			.crop = {
9233145efcdSJacopo Mondi 				.left	= 56,
9243145efcdSJacopo Mondi 				.top	= 6,
9253145efcdSJacopo Mondi 				.width	= 720,
9263145efcdSJacopo Mondi 				.height	= 576,
9273145efcdSJacopo Mondi 			},
9283145efcdSJacopo Mondi 			.htot		= 1896,
9293145efcdSJacopo Mondi 			.vblank_def	= 408,
9305113d5b3SJacopo Mondi 		},
9315113d5b3SJacopo Mondi 		.csi2_timings = {
9325113d5b3SJacopo Mondi 			/* Feed the full valid pixel array to the ISP. */
9335113d5b3SJacopo Mondi 			.analog_crop = {
9345113d5b3SJacopo Mondi 				.left	= OV5640_PIXEL_ARRAY_LEFT,
9355113d5b3SJacopo Mondi 				.top	= OV5640_PIXEL_ARRAY_TOP,
9365113d5b3SJacopo Mondi 				.width	= OV5640_PIXEL_ARRAY_WIDTH,
9375113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
9385113d5b3SJacopo Mondi 			},
9395113d5b3SJacopo Mondi 			.crop = {
9405113d5b3SJacopo Mondi 				.left	= 56,
9415113d5b3SJacopo Mondi 				.top	= 6,
9425113d5b3SJacopo Mondi 				.width	= 720,
9435113d5b3SJacopo Mondi 				.height	= 576,
9445113d5b3SJacopo Mondi 			},
9455113d5b3SJacopo Mondi 			.htot		= 1896,
946961bed9fSJacopo Mondi 			.vblank_def	= 1110,
9475113d5b3SJacopo Mondi 		},
948db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
949db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
95019f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
95119f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
9528409d017SJacopo Mondi 	}, {
9538409d017SJacopo Mondi 		/* 1024x768 */
9543145efcdSJacopo Mondi 		.id		= OV5640_MODE_XGA_1024_768,
9553145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
9563145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
9575113d5b3SJacopo Mondi 		.width		= 1024,
9585113d5b3SJacopo Mondi 		.height		= 768,
9595113d5b3SJacopo Mondi 		.dvp_timings = {
9603145efcdSJacopo Mondi 			.analog_crop = {
9613145efcdSJacopo Mondi 				.left	= 0,
9623145efcdSJacopo Mondi 				.top	= 4,
9633145efcdSJacopo Mondi 				.width	= 2624,
9643145efcdSJacopo Mondi 				.height	= 1944,
9653145efcdSJacopo Mondi 			},
9663145efcdSJacopo Mondi 			.crop = {
9673145efcdSJacopo Mondi 				.left	= 16,
9683145efcdSJacopo Mondi 				.top	= 6,
9693145efcdSJacopo Mondi 				.width	= 1024,
9703145efcdSJacopo Mondi 				.height	= 768,
9713145efcdSJacopo Mondi 			},
9723145efcdSJacopo Mondi 			.htot		= 1896,
9733145efcdSJacopo Mondi 			.vblank_def	= 312,
9745113d5b3SJacopo Mondi 		},
9755113d5b3SJacopo Mondi 		.csi2_timings = {
9765113d5b3SJacopo Mondi 			.analog_crop = {
9775113d5b3SJacopo Mondi 				.left	= 0,
9785113d5b3SJacopo Mondi 				.top	= 4,
9795113d5b3SJacopo Mondi 				.width	= OV5640_NATIVE_WIDTH,
9805113d5b3SJacopo Mondi 				.height	= OV5640_PIXEL_ARRAY_HEIGHT,
9815113d5b3SJacopo Mondi 			},
9825113d5b3SJacopo Mondi 			.crop = {
9835113d5b3SJacopo Mondi 				.left	= 16,
9845113d5b3SJacopo Mondi 				.top	= 6,
9855113d5b3SJacopo Mondi 				.width	= 1024,
9865113d5b3SJacopo Mondi 				.height	= 768,
9875113d5b3SJacopo Mondi 			},
9885113d5b3SJacopo Mondi 			.htot		= 1896,
989961bed9fSJacopo Mondi 			.vblank_def	= 918,
9905113d5b3SJacopo Mondi 		},
991db15c195SJacopo Mondi 		.reg_data	= ov5640_setting_low_res,
992db15c195SJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_low_res),
99319f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
99419f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
9958409d017SJacopo Mondi 	}, {
9968409d017SJacopo Mondi 		/* 1280x720 */
9973145efcdSJacopo Mondi 		.id		= OV5640_MODE_720P_1280_720,
9983145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
9993145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_124M,
10005113d5b3SJacopo Mondi 		.width		= 1280,
10015113d5b3SJacopo Mondi 		.height		= 720,
10025113d5b3SJacopo Mondi 		.dvp_timings = {
10033145efcdSJacopo Mondi 			.analog_crop = {
10043145efcdSJacopo Mondi 				.left	= 0,
10053145efcdSJacopo Mondi 				.top	= 250,
10063145efcdSJacopo Mondi 				.width	= 2624,
10073145efcdSJacopo Mondi 				.height	= 1456,
10083145efcdSJacopo Mondi 			},
10093145efcdSJacopo Mondi 			.crop = {
10103145efcdSJacopo Mondi 				.left	= 16,
10113145efcdSJacopo Mondi 				.top	= 4,
10123145efcdSJacopo Mondi 				.width	= 1280,
10133145efcdSJacopo Mondi 				.height	= 720,
10143145efcdSJacopo Mondi 			},
10153145efcdSJacopo Mondi 			.htot		= 1892,
10163145efcdSJacopo Mondi 			.vblank_def	= 20,
10175113d5b3SJacopo Mondi 		},
10185113d5b3SJacopo Mondi 		.csi2_timings = {
10195113d5b3SJacopo Mondi 			.analog_crop = {
10205113d5b3SJacopo Mondi 				.left	= 0,
10215113d5b3SJacopo Mondi 				.top	= 250,
10225113d5b3SJacopo Mondi 				.width	= 2624,
10235113d5b3SJacopo Mondi 				.height	= 1456,
10245113d5b3SJacopo Mondi 			},
10255113d5b3SJacopo Mondi 			.crop = {
10265113d5b3SJacopo Mondi 				.left	= 16,
10275113d5b3SJacopo Mondi 				.top	= 4,
10285113d5b3SJacopo Mondi 				.width	= 1280,
10295113d5b3SJacopo Mondi 				.height	= 720,
10305113d5b3SJacopo Mondi 			},
1031961bed9fSJacopo Mondi 			.htot		= 1600,
1032961bed9fSJacopo Mondi 			.vblank_def	= 560,
10335113d5b3SJacopo Mondi 		},
10343145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_720P_1280_720,
10353145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_720P_1280_720),
103619f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
103719f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
10388409d017SJacopo Mondi 	}, {
10398409d017SJacopo Mondi 		/* 1920x1080 */
10403145efcdSJacopo Mondi 		.id		= OV5640_MODE_1080P_1920_1080,
10413145efcdSJacopo Mondi 		.dn_mode	= SCALING,
10423145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_148M,
10435113d5b3SJacopo Mondi 		.width		= 1920,
10445113d5b3SJacopo Mondi 		.height		= 1080,
10455113d5b3SJacopo Mondi 		.dvp_timings = {
10463145efcdSJacopo Mondi 			.analog_crop = {
10473145efcdSJacopo Mondi 				.left	= 336,
10483145efcdSJacopo Mondi 				.top	= 434,
10493145efcdSJacopo Mondi 				.width	= 1952,
10503145efcdSJacopo Mondi 				.height	= 1088,
10513145efcdSJacopo Mondi 			},
10523145efcdSJacopo Mondi 			.crop = {
10533145efcdSJacopo Mondi 				.left	= 16,
10543145efcdSJacopo Mondi 				.top	= 4,
10553145efcdSJacopo Mondi 				.width	= 1920,
10563145efcdSJacopo Mondi 				.height	= 1080,
10573145efcdSJacopo Mondi 			},
10583145efcdSJacopo Mondi 			.htot		= 2500,
10593145efcdSJacopo Mondi 			.vblank_def	= 40,
10605113d5b3SJacopo Mondi 		},
10615113d5b3SJacopo Mondi 		.csi2_timings = {
10625113d5b3SJacopo Mondi 			/* Crop the full valid pixel array in the center. */
10635113d5b3SJacopo Mondi 			.analog_crop = {
10645113d5b3SJacopo Mondi 				.left	= 336,
10655113d5b3SJacopo Mondi 				.top	= 434,
10665113d5b3SJacopo Mondi 				.width	= 1952,
10675113d5b3SJacopo Mondi 				.height	= 1088,
10685113d5b3SJacopo Mondi 			},
10695113d5b3SJacopo Mondi 			/* Maintain a larger processing margins. */
10705113d5b3SJacopo Mondi 			.crop = {
10715113d5b3SJacopo Mondi 				.left	= 16,
10725113d5b3SJacopo Mondi 				.top	= 4,
10735113d5b3SJacopo Mondi 				.width	= 1920,
10745113d5b3SJacopo Mondi 				.height	= 1080,
10755113d5b3SJacopo Mondi 			},
1076961bed9fSJacopo Mondi 			.htot		= 2234,
1077961bed9fSJacopo Mondi 			.vblank_def	= 24,
10785113d5b3SJacopo Mondi 		},
10793145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_1080P_1920_1080,
10803145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_1080P_1920_1080),
108119f2e3e6SHugues Fruchet 		.max_fps	= OV5640_30_FPS,
108219f2e3e6SHugues Fruchet 		.def_fps	= OV5640_30_FPS
10838409d017SJacopo Mondi 	}, {
10848409d017SJacopo Mondi 		/* 2592x1944 */
10853145efcdSJacopo Mondi 		.id		= OV5640_MODE_QSXGA_2592_1944,
10863145efcdSJacopo Mondi 		.dn_mode	= SCALING,
10873145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_168M,
10885113d5b3SJacopo Mondi 		.width		= OV5640_PIXEL_ARRAY_WIDTH,
10895113d5b3SJacopo Mondi 		.height		= OV5640_PIXEL_ARRAY_HEIGHT,
10905113d5b3SJacopo Mondi 		.dvp_timings = {
10913145efcdSJacopo Mondi 			.analog_crop = {
10923145efcdSJacopo Mondi 				.left	= 0,
10933145efcdSJacopo Mondi 				.top	= 0,
10943145efcdSJacopo Mondi 				.width	= 2624,
10953145efcdSJacopo Mondi 				.height	= 1952,
10963145efcdSJacopo Mondi 			},
10973145efcdSJacopo Mondi 			.crop = {
10983145efcdSJacopo Mondi 				.left	= 16,
10993145efcdSJacopo Mondi 				.top	= 4,
11003145efcdSJacopo Mondi 				.width	= 2592,
11013145efcdSJacopo Mondi 				.height	= 1944,
11023145efcdSJacopo Mondi 			},
11033145efcdSJacopo Mondi 			.htot		= 2844,
11043145efcdSJacopo Mondi 			.vblank_def	= 24,
11055113d5b3SJacopo Mondi 		},
11065113d5b3SJacopo Mondi 		.csi2_timings = {
11075113d5b3SJacopo Mondi 			/* Give more processing margin to full resolution. */
11085113d5b3SJacopo Mondi 			.analog_crop = {
11095113d5b3SJacopo Mondi 				.left	= 0,
11105113d5b3SJacopo Mondi 				.top	= 0,
11115113d5b3SJacopo Mondi 				.width	= OV5640_NATIVE_WIDTH,
11125113d5b3SJacopo Mondi 				.height	= 1952,
11135113d5b3SJacopo Mondi 			},
11145113d5b3SJacopo Mondi 			.crop = {
11155113d5b3SJacopo Mondi 				.left	= 16,
11165113d5b3SJacopo Mondi 				.top	= 4,
11175113d5b3SJacopo Mondi 				.width	= 2592,
11185113d5b3SJacopo Mondi 				.height	= 1944,
11195113d5b3SJacopo Mondi 			},
11205113d5b3SJacopo Mondi 			.htot		= 2844,
11215113d5b3SJacopo Mondi 			.vblank_def	= 24,
11225113d5b3SJacopo Mondi 		},
11233145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_QSXGA_2592_1944,
11243145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_QSXGA_2592_1944),
112519f2e3e6SHugues Fruchet 		.max_fps	= OV5640_15_FPS,
112619f2e3e6SHugues Fruchet 		.def_fps	= OV5640_15_FPS
11278409d017SJacopo Mondi 	},
112819a81c14SSteve Longerbeam };
112919a81c14SSteve Longerbeam 
11302de6bb97SJacopo Mondi static const struct ov5640_timings *
11312de6bb97SJacopo Mondi ov5640_timings(const struct ov5640_dev *sensor,
11322de6bb97SJacopo Mondi 	       const struct ov5640_mode_info *mode)
11332de6bb97SJacopo Mondi {
11342de6bb97SJacopo Mondi 	if (ov5640_is_csi2(sensor))
11352de6bb97SJacopo Mondi 		return &mode->csi2_timings;
11362de6bb97SJacopo Mondi 
11372de6bb97SJacopo Mondi 	return &mode->dvp_timings;
11382de6bb97SJacopo Mondi }
11392de6bb97SJacopo Mondi 
114019a81c14SSteve Longerbeam static int ov5640_init_slave_id(struct ov5640_dev *sensor)
114119a81c14SSteve Longerbeam {
114219a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
114319a81c14SSteve Longerbeam 	struct i2c_msg msg;
114419a81c14SSteve Longerbeam 	u8 buf[3];
114519a81c14SSteve Longerbeam 	int ret;
114619a81c14SSteve Longerbeam 
114719a81c14SSteve Longerbeam 	if (client->addr == OV5640_DEFAULT_SLAVE_ID)
114819a81c14SSteve Longerbeam 		return 0;
114919a81c14SSteve Longerbeam 
115019a81c14SSteve Longerbeam 	buf[0] = OV5640_REG_SLAVE_ID >> 8;
115119a81c14SSteve Longerbeam 	buf[1] = OV5640_REG_SLAVE_ID & 0xff;
115219a81c14SSteve Longerbeam 	buf[2] = client->addr << 1;
115319a81c14SSteve Longerbeam 
115419a81c14SSteve Longerbeam 	msg.addr = OV5640_DEFAULT_SLAVE_ID;
115519a81c14SSteve Longerbeam 	msg.flags = 0;
115619a81c14SSteve Longerbeam 	msg.buf = buf;
115719a81c14SSteve Longerbeam 	msg.len = sizeof(buf);
115819a81c14SSteve Longerbeam 
115919a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, &msg, 1);
116019a81c14SSteve Longerbeam 	if (ret < 0) {
116119a81c14SSteve Longerbeam 		dev_err(&client->dev, "%s: failed with %d\n", __func__, ret);
116219a81c14SSteve Longerbeam 		return ret;
116319a81c14SSteve Longerbeam 	}
116419a81c14SSteve Longerbeam 
116519a81c14SSteve Longerbeam 	return 0;
116619a81c14SSteve Longerbeam }
116719a81c14SSteve Longerbeam 
116819a81c14SSteve Longerbeam static int ov5640_write_reg(struct ov5640_dev *sensor, u16 reg, u8 val)
116919a81c14SSteve Longerbeam {
117019a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
117119a81c14SSteve Longerbeam 	struct i2c_msg msg;
117219a81c14SSteve Longerbeam 	u8 buf[3];
117319a81c14SSteve Longerbeam 	int ret;
117419a81c14SSteve Longerbeam 
117519a81c14SSteve Longerbeam 	buf[0] = reg >> 8;
117619a81c14SSteve Longerbeam 	buf[1] = reg & 0xff;
117719a81c14SSteve Longerbeam 	buf[2] = val;
117819a81c14SSteve Longerbeam 
117919a81c14SSteve Longerbeam 	msg.addr = client->addr;
118019a81c14SSteve Longerbeam 	msg.flags = client->flags;
118119a81c14SSteve Longerbeam 	msg.buf = buf;
118219a81c14SSteve Longerbeam 	msg.len = sizeof(buf);
118319a81c14SSteve Longerbeam 
118419a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, &msg, 1);
118519a81c14SSteve Longerbeam 	if (ret < 0) {
11863924c623SHugues Fruchet 		dev_err(&client->dev, "%s: error: reg=%x, val=%x\n",
118719a81c14SSteve Longerbeam 			__func__, reg, val);
118819a81c14SSteve Longerbeam 		return ret;
118919a81c14SSteve Longerbeam 	}
119019a81c14SSteve Longerbeam 
119119a81c14SSteve Longerbeam 	return 0;
119219a81c14SSteve Longerbeam }
119319a81c14SSteve Longerbeam 
119419a81c14SSteve Longerbeam static int ov5640_read_reg(struct ov5640_dev *sensor, u16 reg, u8 *val)
119519a81c14SSteve Longerbeam {
119619a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
119719a81c14SSteve Longerbeam 	struct i2c_msg msg[2];
119819a81c14SSteve Longerbeam 	u8 buf[2];
119919a81c14SSteve Longerbeam 	int ret;
120019a81c14SSteve Longerbeam 
120119a81c14SSteve Longerbeam 	buf[0] = reg >> 8;
120219a81c14SSteve Longerbeam 	buf[1] = reg & 0xff;
120319a81c14SSteve Longerbeam 
120419a81c14SSteve Longerbeam 	msg[0].addr = client->addr;
120519a81c14SSteve Longerbeam 	msg[0].flags = client->flags;
120619a81c14SSteve Longerbeam 	msg[0].buf = buf;
120719a81c14SSteve Longerbeam 	msg[0].len = sizeof(buf);
120819a81c14SSteve Longerbeam 
120919a81c14SSteve Longerbeam 	msg[1].addr = client->addr;
121019a81c14SSteve Longerbeam 	msg[1].flags = client->flags | I2C_M_RD;
121119a81c14SSteve Longerbeam 	msg[1].buf = buf;
121219a81c14SSteve Longerbeam 	msg[1].len = 1;
121319a81c14SSteve Longerbeam 
121419a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, msg, 2);
12153924c623SHugues Fruchet 	if (ret < 0) {
12163924c623SHugues Fruchet 		dev_err(&client->dev, "%s: error: reg=%x\n",
12173924c623SHugues Fruchet 			__func__, reg);
121819a81c14SSteve Longerbeam 		return ret;
12193924c623SHugues Fruchet 	}
122019a81c14SSteve Longerbeam 
122119a81c14SSteve Longerbeam 	*val = buf[0];
122219a81c14SSteve Longerbeam 	return 0;
122319a81c14SSteve Longerbeam }
122419a81c14SSteve Longerbeam 
122519a81c14SSteve Longerbeam static int ov5640_read_reg16(struct ov5640_dev *sensor, u16 reg, u16 *val)
122619a81c14SSteve Longerbeam {
122719a81c14SSteve Longerbeam 	u8 hi, lo;
122819a81c14SSteve Longerbeam 	int ret;
122919a81c14SSteve Longerbeam 
123019a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg, &hi);
123119a81c14SSteve Longerbeam 	if (ret)
123219a81c14SSteve Longerbeam 		return ret;
123319a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg + 1, &lo);
123419a81c14SSteve Longerbeam 	if (ret)
123519a81c14SSteve Longerbeam 		return ret;
123619a81c14SSteve Longerbeam 
123719a81c14SSteve Longerbeam 	*val = ((u16)hi << 8) | (u16)lo;
123819a81c14SSteve Longerbeam 	return 0;
123919a81c14SSteve Longerbeam }
124019a81c14SSteve Longerbeam 
124119a81c14SSteve Longerbeam static int ov5640_write_reg16(struct ov5640_dev *sensor, u16 reg, u16 val)
124219a81c14SSteve Longerbeam {
124319a81c14SSteve Longerbeam 	int ret;
124419a81c14SSteve Longerbeam 
124519a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, reg, val >> 8);
124619a81c14SSteve Longerbeam 	if (ret)
124719a81c14SSteve Longerbeam 		return ret;
124819a81c14SSteve Longerbeam 
124919a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, reg + 1, val & 0xff);
125019a81c14SSteve Longerbeam }
125119a81c14SSteve Longerbeam 
125219a81c14SSteve Longerbeam static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg,
125319a81c14SSteve Longerbeam 			  u8 mask, u8 val)
125419a81c14SSteve Longerbeam {
125519a81c14SSteve Longerbeam 	u8 readval;
125619a81c14SSteve Longerbeam 	int ret;
125719a81c14SSteve Longerbeam 
125819a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg, &readval);
125919a81c14SSteve Longerbeam 	if (ret)
126019a81c14SSteve Longerbeam 		return ret;
126119a81c14SSteve Longerbeam 
126219a81c14SSteve Longerbeam 	readval &= ~mask;
126319a81c14SSteve Longerbeam 	val &= mask;
126419a81c14SSteve Longerbeam 	val |= readval;
126519a81c14SSteve Longerbeam 
126619a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, reg, val);
126719a81c14SSteve Longerbeam }
126819a81c14SSteve Longerbeam 
1269aa288248SMaxime Ripard /*
1270aa288248SMaxime Ripard  * After trying the various combinations, reading various
1271f8a7647dSMauro Carvalho Chehab  * documentations spread around the net, and from the various
1272aa288248SMaxime Ripard  * feedback, the clock tree is probably as follows:
1273aa288248SMaxime Ripard  *
1274aa288248SMaxime Ripard  *   +--------------+
1275aa288248SMaxime Ripard  *   |  Ext. Clock  |
1276aa288248SMaxime Ripard  *   +-+------------+
1277aa288248SMaxime Ripard  *     |  +----------+
1278aa288248SMaxime Ripard  *     +->|   PLL1   | - reg 0x3036, for the multiplier
1279aa288248SMaxime Ripard  *        +-+--------+ - reg 0x3037, bits 0-3 for the pre-divider
1280aa288248SMaxime Ripard  *          |  +--------------+
1281aa288248SMaxime Ripard  *          +->| System Clock |  - reg 0x3035, bits 4-7
1282aa288248SMaxime Ripard  *             +-+------------+
1283aa288248SMaxime Ripard  *               |  +--------------+
1284aa288248SMaxime Ripard  *               +->| MIPI Divider | - reg 0x3035, bits 0-3
1285aa288248SMaxime Ripard  *               |  +-+------------+
1286aa288248SMaxime Ripard  *               |    +----------------> MIPI SCLK
1287aa288248SMaxime Ripard  *               |    +  +-----+
1288aa288248SMaxime Ripard  *               |    +->| / 2 |-------> MIPI BIT CLK
1289aa288248SMaxime Ripard  *               |       +-----+
1290aa288248SMaxime Ripard  *               |  +--------------+
1291aa288248SMaxime Ripard  *               +->| PLL Root Div | - reg 0x3037, bit 4
1292aa288248SMaxime Ripard  *                  +-+------------+
1293aa288248SMaxime Ripard  *                    |  +---------+
12944c85f628SPaul Kocialkowski  *                    +->| Bit Div | - reg 0x3034, bits 0-3
1295aa288248SMaxime Ripard  *                       +-+-------+
1296aa288248SMaxime Ripard  *                         |  +-------------+
1297aa288248SMaxime Ripard  *                         +->| SCLK Div    | - reg 0x3108, bits 0-1
1298aa288248SMaxime Ripard  *                         |  +-+-----------+
1299aa288248SMaxime Ripard  *                         |    +---------------> SCLK
1300aa288248SMaxime Ripard  *                         |  +-------------+
1301aa288248SMaxime Ripard  *                         +->| SCLK 2X Div | - reg 0x3108, bits 2-3
1302aa288248SMaxime Ripard  *                         |  +-+-----------+
1303aa288248SMaxime Ripard  *                         |    +---------------> SCLK 2X
1304aa288248SMaxime Ripard  *                         |  +-------------+
1305aa288248SMaxime Ripard  *                         +->| PCLK Div    | - reg 0x3108, bits 4-5
1306aa288248SMaxime Ripard  *                            ++------------+
1307aa288248SMaxime Ripard  *                             +  +-----------+
1308aa288248SMaxime Ripard  *                             +->|   P_DIV   | - reg 0x3035, bits 0-3
1309aa288248SMaxime Ripard  *                                +-----+-----+
1310aa288248SMaxime Ripard  *                                       +------------> PCLK
1311aa288248SMaxime Ripard  *
13126c957ed7SJacopo Mondi  * There seems to be also constraints:
1313aa288248SMaxime Ripard  *  - the PLL pre-divider output rate should be in the 4-27MHz range
1314aa288248SMaxime Ripard  *  - the PLL multiplier output rate should be in the 500-1000MHz range
1315aa288248SMaxime Ripard  *  - PCLK >= SCLK * 2 in YUV, >= SCLK in Raw or JPEG
1316aa288248SMaxime Ripard  */
1317aa288248SMaxime Ripard 
1318aa288248SMaxime Ripard /*
1319aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1320aa288248SMaxime Ripard  * set to 3 in the vendor kernels.
1321aa288248SMaxime Ripard  */
1322aa288248SMaxime Ripard #define OV5640_PLL_PREDIV	3
1323aa288248SMaxime Ripard 
1324aa288248SMaxime Ripard #define OV5640_PLL_MULT_MIN	4
1325aa288248SMaxime Ripard #define OV5640_PLL_MULT_MAX	252
1326aa288248SMaxime Ripard 
1327aa288248SMaxime Ripard /*
1328aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 16, but the value is
1329aa288248SMaxime Ripard  * always set to either 1 or 2 in the vendor kernels.
1330aa288248SMaxime Ripard  */
1331aa288248SMaxime Ripard #define OV5640_SYSDIV_MIN	1
1332aa288248SMaxime Ripard #define OV5640_SYSDIV_MAX	16
1333aa288248SMaxime Ripard 
1334aa288248SMaxime Ripard /*
1335aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 2, but the value is always
1336aa288248SMaxime Ripard  * set to 2 in the vendor kernels.
1337aa288248SMaxime Ripard  */
1338aa288248SMaxime Ripard #define OV5640_PLL_ROOT_DIV			2
1339aa288248SMaxime Ripard #define OV5640_PLL_CTRL3_PLL_ROOT_DIV_2		BIT(4)
1340aa288248SMaxime Ripard 
1341aa288248SMaxime Ripard /*
1342aa288248SMaxime Ripard  * We only supports 8-bit formats at the moment
1343aa288248SMaxime Ripard  */
1344aa288248SMaxime Ripard #define OV5640_BIT_DIV				2
1345aa288248SMaxime Ripard #define OV5640_PLL_CTRL0_MIPI_MODE_8BIT		0x08
1346aa288248SMaxime Ripard 
1347aa288248SMaxime Ripard /*
1348aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1349aa288248SMaxime Ripard  * set to 2 in the vendor kernels.
1350aa288248SMaxime Ripard  */
1351aa288248SMaxime Ripard #define OV5640_SCLK_ROOT_DIV	2
1352aa288248SMaxime Ripard 
1353aa288248SMaxime Ripard /*
1354aa288248SMaxime Ripard  * This is hardcoded so that the consistency is maintained between SCLK and
1355aa288248SMaxime Ripard  * SCLK 2x.
1356aa288248SMaxime Ripard  */
1357aa288248SMaxime Ripard #define OV5640_SCLK2X_ROOT_DIV (OV5640_SCLK_ROOT_DIV / 2)
1358aa288248SMaxime Ripard 
1359aa288248SMaxime Ripard /*
1360aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1361aa288248SMaxime Ripard  * set to 1 in the vendor kernels.
1362aa288248SMaxime Ripard  */
1363aa288248SMaxime Ripard #define OV5640_PCLK_ROOT_DIV			1
1364aa288248SMaxime Ripard #define OV5640_PLL_SYS_ROOT_DIVIDER_BYPASS	0x00
1365aa288248SMaxime Ripard 
1366aa288248SMaxime Ripard static unsigned long ov5640_compute_sys_clk(struct ov5640_dev *sensor,
1367aa288248SMaxime Ripard 					    u8 pll_prediv, u8 pll_mult,
1368aa288248SMaxime Ripard 					    u8 sysdiv)
1369aa288248SMaxime Ripard {
1370aa288248SMaxime Ripard 	unsigned long sysclk = sensor->xclk_freq / pll_prediv * pll_mult;
1371aa288248SMaxime Ripard 
1372aa288248SMaxime Ripard 	/* PLL1 output cannot exceed 1GHz. */
1373aa288248SMaxime Ripard 	if (sysclk / 1000000 > 1000)
1374aa288248SMaxime Ripard 		return 0;
1375aa288248SMaxime Ripard 
1376aa288248SMaxime Ripard 	return sysclk / sysdiv;
1377aa288248SMaxime Ripard }
1378aa288248SMaxime Ripard 
1379aa288248SMaxime Ripard static unsigned long ov5640_calc_sys_clk(struct ov5640_dev *sensor,
1380aa288248SMaxime Ripard 					 unsigned long rate,
1381aa288248SMaxime Ripard 					 u8 *pll_prediv, u8 *pll_mult,
1382aa288248SMaxime Ripard 					 u8 *sysdiv)
1383aa288248SMaxime Ripard {
1384aa288248SMaxime Ripard 	unsigned long best = ~0;
1385aa288248SMaxime Ripard 	u8 best_sysdiv = 1, best_mult = 1;
1386aa288248SMaxime Ripard 	u8 _sysdiv, _pll_mult;
1387aa288248SMaxime Ripard 
1388aa288248SMaxime Ripard 	for (_sysdiv = OV5640_SYSDIV_MIN;
1389aa288248SMaxime Ripard 	     _sysdiv <= OV5640_SYSDIV_MAX;
1390aa288248SMaxime Ripard 	     _sysdiv++) {
1391aa288248SMaxime Ripard 		for (_pll_mult = OV5640_PLL_MULT_MIN;
1392aa288248SMaxime Ripard 		     _pll_mult <= OV5640_PLL_MULT_MAX;
1393aa288248SMaxime Ripard 		     _pll_mult++) {
1394aa288248SMaxime Ripard 			unsigned long _rate;
1395aa288248SMaxime Ripard 
1396aa288248SMaxime Ripard 			/*
1397aa288248SMaxime Ripard 			 * The PLL multiplier cannot be odd if above
1398aa288248SMaxime Ripard 			 * 127.
1399aa288248SMaxime Ripard 			 */
1400aa288248SMaxime Ripard 			if (_pll_mult > 127 && (_pll_mult % 2))
1401aa288248SMaxime Ripard 				continue;
1402aa288248SMaxime Ripard 
1403aa288248SMaxime Ripard 			_rate = ov5640_compute_sys_clk(sensor,
1404aa288248SMaxime Ripard 						       OV5640_PLL_PREDIV,
1405aa288248SMaxime Ripard 						       _pll_mult, _sysdiv);
1406aa288248SMaxime Ripard 
1407aa288248SMaxime Ripard 			/*
1408aa288248SMaxime Ripard 			 * We have reached the maximum allowed PLL1 output,
1409aa288248SMaxime Ripard 			 * increase sysdiv.
1410aa288248SMaxime Ripard 			 */
14112e3df204SAdam Ford 			if (!_rate)
1412aa288248SMaxime Ripard 				break;
1413aa288248SMaxime Ripard 
1414aa288248SMaxime Ripard 			/*
1415aa288248SMaxime Ripard 			 * Prefer rates above the expected clock rate than
1416aa288248SMaxime Ripard 			 * below, even if that means being less precise.
1417aa288248SMaxime Ripard 			 */
1418aa288248SMaxime Ripard 			if (_rate < rate)
1419aa288248SMaxime Ripard 				continue;
1420aa288248SMaxime Ripard 
1421aa288248SMaxime Ripard 			if (abs(rate - _rate) < abs(rate - best)) {
1422aa288248SMaxime Ripard 				best = _rate;
1423aa288248SMaxime Ripard 				best_sysdiv = _sysdiv;
1424aa288248SMaxime Ripard 				best_mult = _pll_mult;
1425aa288248SMaxime Ripard 			}
1426aa288248SMaxime Ripard 
1427aa288248SMaxime Ripard 			if (_rate == rate)
1428aa288248SMaxime Ripard 				goto out;
1429aa288248SMaxime Ripard 		}
1430aa288248SMaxime Ripard 	}
1431aa288248SMaxime Ripard 
1432aa288248SMaxime Ripard out:
1433aa288248SMaxime Ripard 	*sysdiv = best_sysdiv;
1434aa288248SMaxime Ripard 	*pll_prediv = OV5640_PLL_PREDIV;
1435aa288248SMaxime Ripard 	*pll_mult = best_mult;
1436aa288248SMaxime Ripard 
1437aa288248SMaxime Ripard 	return best;
1438aa288248SMaxime Ripard }
1439aa288248SMaxime Ripard 
1440aa288248SMaxime Ripard /*
1441aa288248SMaxime Ripard  * ov5640_set_mipi_pclk() - Calculate the clock tree configuration values
1442aa288248SMaxime Ripard  *			    for the MIPI CSI-2 output.
1443aa288248SMaxime Ripard  */
14446c957ed7SJacopo Mondi static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor)
1445aa288248SMaxime Ripard {
14466c957ed7SJacopo Mondi 	u8 bit_div, mipi_div, pclk_div, sclk_div, sclk2x_div, root_div;
1447aa288248SMaxime Ripard 	u8 prediv, mult, sysdiv;
14486c957ed7SJacopo Mondi 	unsigned long link_freq;
14496c957ed7SJacopo Mondi 	unsigned long sysclk;
14506c957ed7SJacopo Mondi 	u8 pclk_period;
14516c957ed7SJacopo Mondi 	u32 sample_rate;
14526c957ed7SJacopo Mondi 	u32 num_lanes;
1453aa288248SMaxime Ripard 	int ret;
1454aa288248SMaxime Ripard 
14556c957ed7SJacopo Mondi 	/* Use the link freq computed at ov5640_update_pixel_rate() time. */
14566c957ed7SJacopo Mondi 	link_freq = sensor->current_link_freq;
14576c957ed7SJacopo Mondi 
1458aa288248SMaxime Ripard 	/*
14596c957ed7SJacopo Mondi 	 * - mipi_div - Additional divider for the MIPI lane clock.
14606c957ed7SJacopo Mondi 	 *
14616c957ed7SJacopo Mondi 	 * Higher link frequencies would make sysclk > 1GHz.
14626c957ed7SJacopo Mondi 	 * Keep the sysclk low and do not divide in the MIPI domain.
1463aa288248SMaxime Ripard 	 */
14646c957ed7SJacopo Mondi 	if (link_freq > OV5640_LINK_RATE_MAX)
14656c957ed7SJacopo Mondi 		mipi_div = 1;
1466aa288248SMaxime Ripard 	else
14676c957ed7SJacopo Mondi 		mipi_div = 2;
1468aa288248SMaxime Ripard 
14696c957ed7SJacopo Mondi 	sysclk = link_freq * mipi_div;
14706c957ed7SJacopo Mondi 	ov5640_calc_sys_clk(sensor, sysclk, &prediv, &mult, &sysdiv);
1471aa288248SMaxime Ripard 
14726c957ed7SJacopo Mondi 	/*
14736c957ed7SJacopo Mondi 	 * Adjust PLL parameters to maintain the MIPI_SCLK-to-PCLK ratio.
14746c957ed7SJacopo Mondi 	 *
14756c957ed7SJacopo Mondi 	 * - root_div = 2 (fixed)
14766c957ed7SJacopo Mondi 	 * - bit_div : MIPI 8-bit = 2; MIPI 10-bit = 2.5
14776c957ed7SJacopo Mondi 	 * - pclk_div = 1 (fixed)
14786c957ed7SJacopo Mondi 	 * - p_div  = (2 lanes ? mipi_div : 2 * mipi_div)
14796c957ed7SJacopo Mondi 	 *
14806c957ed7SJacopo Mondi 	 * This results in the following MIPI_SCLK depending on the number
14816c957ed7SJacopo Mondi 	 * of lanes:
14826c957ed7SJacopo Mondi 	 *
14836c957ed7SJacopo Mondi 	 * - 2 lanes: MIPI_SCLK = (4 or 5) * PCLK
14846c957ed7SJacopo Mondi 	 * - 1 lanes: MIPI_SCLK = (8 or 10) * PCLK
14856c957ed7SJacopo Mondi 	 */
14866c957ed7SJacopo Mondi 	root_div = OV5640_PLL_CTRL3_PLL_ROOT_DIV_2;
14876c957ed7SJacopo Mondi 	bit_div =  OV5640_PLL_CTRL0_MIPI_MODE_8BIT;
14886c957ed7SJacopo Mondi 	pclk_div = ilog2(OV5640_PCLK_ROOT_DIV);
1489aa288248SMaxime Ripard 
14906c957ed7SJacopo Mondi 	/*
14916c957ed7SJacopo Mondi 	 * Scaler clock:
14926c957ed7SJacopo Mondi 	 * - YUV: PCLK >= 2 * SCLK
14936c957ed7SJacopo Mondi 	 * - RAW or JPEG: PCLK >= SCLK
14946c957ed7SJacopo Mondi 	 * - sclk2x_div = sclk_div / 2
14956c957ed7SJacopo Mondi 	 */
14966c957ed7SJacopo Mondi 	sclk_div = ilog2(OV5640_SCLK_ROOT_DIV);
14976c957ed7SJacopo Mondi 	sclk2x_div = ilog2(OV5640_SCLK2X_ROOT_DIV);
14986c957ed7SJacopo Mondi 
14996c957ed7SJacopo Mondi 	/*
15006c957ed7SJacopo Mondi 	 * Set the pixel clock period expressed in ns with 1-bit decimal
15016c957ed7SJacopo Mondi 	 * (0x01=0.5ns).
15026c957ed7SJacopo Mondi 	 *
15036c957ed7SJacopo Mondi 	 * The register is very briefly documented. In the OV5645 datasheet it
15046c957ed7SJacopo Mondi 	 * is described as (2 * pclk period), and from testing it seems the
15056c957ed7SJacopo Mondi 	 * actual definition is 2 * 8-bit sample period.
15066c957ed7SJacopo Mondi 	 *
15076c957ed7SJacopo Mondi 	 * 2 * sample_period = (mipi_clk * 2 * num_lanes / bpp) * (bpp / 8) / 2
15086c957ed7SJacopo Mondi 	 */
15096c957ed7SJacopo Mondi 	num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes;
15106c957ed7SJacopo Mondi 	sample_rate = (link_freq * mipi_div * num_lanes * 2) / 16;
15116c957ed7SJacopo Mondi 	pclk_period = 2000000000UL / sample_rate;
15126c957ed7SJacopo Mondi 
15136c957ed7SJacopo Mondi 	/* Program the clock tree registers. */
15146c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0, 0x0f, bit_div);
15156c957ed7SJacopo Mondi 	if (ret)
15166c957ed7SJacopo Mondi 		return ret;
15176c957ed7SJacopo Mondi 
15186c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, 0xff,
15196c957ed7SJacopo Mondi 			     (sysdiv << 4) | mipi_div);
1520aa288248SMaxime Ripard 	if (ret)
1521aa288248SMaxime Ripard 		return ret;
1522aa288248SMaxime Ripard 
1523aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2, 0xff, mult);
1524aa288248SMaxime Ripard 	if (ret)
1525aa288248SMaxime Ripard 		return ret;
1526aa288248SMaxime Ripard 
15276c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3, 0x1f,
15286c957ed7SJacopo Mondi 			     root_div | prediv);
1529aa288248SMaxime Ripard 	if (ret)
1530aa288248SMaxime Ripard 		return ret;
1531aa288248SMaxime Ripard 
15326c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
15336c957ed7SJacopo Mondi 			     (pclk_div << 4) | (sclk2x_div << 2) | sclk_div);
15346c957ed7SJacopo Mondi 	if (ret)
15356c957ed7SJacopo Mondi 		return ret;
15366c957ed7SJacopo Mondi 
15376c957ed7SJacopo Mondi 	return ov5640_write_reg(sensor, OV5640_REG_PCLK_PERIOD, pclk_period);
15386c957ed7SJacopo Mondi }
15396c957ed7SJacopo Mondi 
15406c957ed7SJacopo Mondi static u32 ov5640_calc_pixel_rate(struct ov5640_dev *sensor)
15416c957ed7SJacopo Mondi {
15423145efcdSJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
15435113d5b3SJacopo Mondi 	const struct ov5640_timings *timings = &mode->dvp_timings;
15446c957ed7SJacopo Mondi 	u32 rate;
15456c957ed7SJacopo Mondi 
15465113d5b3SJacopo Mondi 	rate = timings->htot * (timings->crop.height + timings->vblank_def);
15476c957ed7SJacopo Mondi 	rate *= ov5640_framerates[sensor->current_fr];
15486c957ed7SJacopo Mondi 
15496c957ed7SJacopo Mondi 	return rate;
1550aa288248SMaxime Ripard }
1551aa288248SMaxime Ripard 
1552aa288248SMaxime Ripard static unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor,
1553aa288248SMaxime Ripard 				      unsigned long rate,
1554aa288248SMaxime Ripard 				      u8 *pll_prediv, u8 *pll_mult, u8 *sysdiv,
1555aa288248SMaxime Ripard 				      u8 *pll_rdiv, u8 *bit_div, u8 *pclk_div)
1556aa288248SMaxime Ripard {
1557aa288248SMaxime Ripard 	unsigned long _rate = rate * OV5640_PLL_ROOT_DIV * OV5640_BIT_DIV *
1558aa288248SMaxime Ripard 				OV5640_PCLK_ROOT_DIV;
1559aa288248SMaxime Ripard 
1560aa288248SMaxime Ripard 	_rate = ov5640_calc_sys_clk(sensor, _rate, pll_prediv, pll_mult,
1561aa288248SMaxime Ripard 				    sysdiv);
1562aa288248SMaxime Ripard 	*pll_rdiv = OV5640_PLL_ROOT_DIV;
1563aa288248SMaxime Ripard 	*bit_div = OV5640_BIT_DIV;
1564aa288248SMaxime Ripard 	*pclk_div = OV5640_PCLK_ROOT_DIV;
1565aa288248SMaxime Ripard 
1566aa288248SMaxime Ripard 	return _rate / *pll_rdiv / *bit_div / *pclk_div;
1567aa288248SMaxime Ripard }
1568aa288248SMaxime Ripard 
15696c957ed7SJacopo Mondi static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor)
1570aa288248SMaxime Ripard {
1571aa288248SMaxime Ripard 	u8 prediv, mult, sysdiv, pll_rdiv, bit_div, pclk_div;
15726c957ed7SJacopo Mondi 	u32 rate;
1573aa288248SMaxime Ripard 	int ret;
1574aa288248SMaxime Ripard 
15756c957ed7SJacopo Mondi 	rate = ov5640_calc_pixel_rate(sensor);
1576a89f14bbSJacopo Mondi 	rate *= ov5640_code_to_bpp(sensor, sensor->fmt.code);
15776c957ed7SJacopo Mondi 	rate /= sensor->ep.bus.parallel.bus_width;
15786c957ed7SJacopo Mondi 
1579aa288248SMaxime Ripard 	ov5640_calc_pclk(sensor, rate, &prediv, &mult, &sysdiv, &pll_rdiv,
1580aa288248SMaxime Ripard 			 &bit_div, &pclk_div);
1581aa288248SMaxime Ripard 
1582aa288248SMaxime Ripard 	if (bit_div == 2)
1583aa288248SMaxime Ripard 		bit_div = 8;
1584aa288248SMaxime Ripard 
1585aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0,
1586aa288248SMaxime Ripard 			     0x0f, bit_div);
1587aa288248SMaxime Ripard 	if (ret)
1588aa288248SMaxime Ripard 		return ret;
1589aa288248SMaxime Ripard 
1590aa288248SMaxime Ripard 	/*
1591aa288248SMaxime Ripard 	 * We need to set sysdiv according to the clock, and to clear
1592aa288248SMaxime Ripard 	 * the MIPI divider.
1593aa288248SMaxime Ripard 	 */
1594aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1,
1595aa288248SMaxime Ripard 			     0xff, sysdiv << 4);
1596aa288248SMaxime Ripard 	if (ret)
1597aa288248SMaxime Ripard 		return ret;
1598aa288248SMaxime Ripard 
1599aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2,
1600aa288248SMaxime Ripard 			     0xff, mult);
1601aa288248SMaxime Ripard 	if (ret)
1602aa288248SMaxime Ripard 		return ret;
1603aa288248SMaxime Ripard 
1604aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3,
1605aa288248SMaxime Ripard 			     0x1f, prediv | ((pll_rdiv - 1) << 4));
1606aa288248SMaxime Ripard 	if (ret)
1607aa288248SMaxime Ripard 		return ret;
1608aa288248SMaxime Ripard 
1609aa288248SMaxime Ripard 	return ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x30,
1610aa288248SMaxime Ripard 			      (ilog2(pclk_div) << 4));
1611aa288248SMaxime Ripard }
1612aa288248SMaxime Ripard 
16137cb013b1SChen-Yu Tsai /* set JPEG framing sizes */
16147cb013b1SChen-Yu Tsai static int ov5640_set_jpeg_timings(struct ov5640_dev *sensor,
16157cb013b1SChen-Yu Tsai 				   const struct ov5640_mode_info *mode)
16167cb013b1SChen-Yu Tsai {
16177cb013b1SChen-Yu Tsai 	int ret;
16187cb013b1SChen-Yu Tsai 
16192b5c18f9SChen-Yu Tsai 	/*
16202b5c18f9SChen-Yu Tsai 	 * compression mode 3 timing
16212b5c18f9SChen-Yu Tsai 	 *
16222b5c18f9SChen-Yu Tsai 	 * Data is transmitted with programmable width (VFIFO_HSIZE).
16232b5c18f9SChen-Yu Tsai 	 * No padding done. Last line may have less data. Varying
16242b5c18f9SChen-Yu Tsai 	 * number of lines per frame, depending on amount of data.
16252b5c18f9SChen-Yu Tsai 	 */
16262b5c18f9SChen-Yu Tsai 	ret = ov5640_mod_reg(sensor, OV5640_REG_JPG_MODE_SELECT, 0x7, 0x3);
16272b5c18f9SChen-Yu Tsai 	if (ret < 0)
16282b5c18f9SChen-Yu Tsai 		return ret;
16292b5c18f9SChen-Yu Tsai 
16305113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_VFIFO_HSIZE, mode->width);
16317cb013b1SChen-Yu Tsai 	if (ret < 0)
16327cb013b1SChen-Yu Tsai 		return ret;
16337cb013b1SChen-Yu Tsai 
16345113d5b3SJacopo Mondi 	return ov5640_write_reg16(sensor, OV5640_REG_VFIFO_VSIZE, mode->height);
16357cb013b1SChen-Yu Tsai }
16367cb013b1SChen-Yu Tsai 
163719a81c14SSteve Longerbeam /* download ov5640 settings to sensor through i2c */
1638bad1774eSJacopo Mondi static int ov5640_set_timings(struct ov5640_dev *sensor,
1639bad1774eSJacopo Mondi 			      const struct ov5640_mode_info *mode)
1640bad1774eSJacopo Mondi {
16415113d5b3SJacopo Mondi 	const struct ov5640_timings *timings;
16425113d5b3SJacopo Mondi 	const struct v4l2_rect *analog_crop;
16435113d5b3SJacopo Mondi 	const struct v4l2_rect *crop;
1644bad1774eSJacopo Mondi 	int ret;
1645bad1774eSJacopo Mondi 
16467cb013b1SChen-Yu Tsai 	if (sensor->fmt.code == MEDIA_BUS_FMT_JPEG_1X8) {
16477cb013b1SChen-Yu Tsai 		ret = ov5640_set_jpeg_timings(sensor, mode);
16487cb013b1SChen-Yu Tsai 		if (ret < 0)
16497cb013b1SChen-Yu Tsai 			return ret;
16507cb013b1SChen-Yu Tsai 	}
16517cb013b1SChen-Yu Tsai 
16522de6bb97SJacopo Mondi 	timings = ov5640_timings(sensor, mode);
16535113d5b3SJacopo Mondi 	analog_crop = &timings->analog_crop;
16545113d5b3SJacopo Mondi 	crop = &timings->crop;
16555113d5b3SJacopo Mondi 
16563145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HS,
16573145efcdSJacopo Mondi 				 analog_crop->left);
1658bad1774eSJacopo Mondi 	if (ret < 0)
1659bad1774eSJacopo Mondi 		return ret;
1660bad1774eSJacopo Mondi 
16613145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VS,
16623145efcdSJacopo Mondi 				 analog_crop->top);
16633145efcdSJacopo Mondi 	if (ret < 0)
16643145efcdSJacopo Mondi 		return ret;
16653145efcdSJacopo Mondi 
16663145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HW,
16673145efcdSJacopo Mondi 				 analog_crop->left + analog_crop->width - 1);
16683145efcdSJacopo Mondi 	if (ret < 0)
16693145efcdSJacopo Mondi 		return ret;
16703145efcdSJacopo Mondi 
16713145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VH,
16723145efcdSJacopo Mondi 				 analog_crop->top + analog_crop->height - 1);
16733145efcdSJacopo Mondi 	if (ret < 0)
16743145efcdSJacopo Mondi 		return ret;
16753145efcdSJacopo Mondi 
16763145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HOFFS, crop->left);
16773145efcdSJacopo Mondi 	if (ret < 0)
16783145efcdSJacopo Mondi 		return ret;
16793145efcdSJacopo Mondi 
16803145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VOFFS, crop->top);
16813145efcdSJacopo Mondi 	if (ret < 0)
16823145efcdSJacopo Mondi 		return ret;
16833145efcdSJacopo Mondi 
16845113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->width);
16853145efcdSJacopo Mondi 	if (ret < 0)
16863145efcdSJacopo Mondi 		return ret;
16873145efcdSJacopo Mondi 
16885113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, mode->height);
1689bad1774eSJacopo Mondi 	if (ret < 0)
1690bad1774eSJacopo Mondi 		return ret;
1691bad1774eSJacopo Mondi 
16925113d5b3SJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, timings->htot);
1693bad1774eSJacopo Mondi 	if (ret < 0)
1694bad1774eSJacopo Mondi 		return ret;
1695bad1774eSJacopo Mondi 
16963145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS,
16975113d5b3SJacopo Mondi 				 mode->height + timings->vblank_def);
16983145efcdSJacopo Mondi 	if (ret < 0)
16993145efcdSJacopo Mondi 		return ret;
17003145efcdSJacopo Mondi 
17013145efcdSJacopo Mondi 	return 0;
1702bad1774eSJacopo Mondi }
1703bad1774eSJacopo Mondi 
1704e4359019SJacopo Mondi static void ov5640_load_regs(struct ov5640_dev *sensor,
1705e4359019SJacopo Mondi 			     const struct reg_value *regs, unsigned int regnum)
170619a81c14SSteve Longerbeam {
170719a81c14SSteve Longerbeam 	unsigned int i;
170819a81c14SSteve Longerbeam 	u32 delay_ms;
170919a81c14SSteve Longerbeam 	u16 reg_addr;
171019a81c14SSteve Longerbeam 	u8 mask, val;
171119a81c14SSteve Longerbeam 	int ret = 0;
171219a81c14SSteve Longerbeam 
1713e4359019SJacopo Mondi 	for (i = 0; i < regnum; ++i, ++regs) {
171419a81c14SSteve Longerbeam 		delay_ms = regs->delay_ms;
171519a81c14SSteve Longerbeam 		reg_addr = regs->reg_addr;
171619a81c14SSteve Longerbeam 		val = regs->val;
171719a81c14SSteve Longerbeam 		mask = regs->mask;
171819a81c14SSteve Longerbeam 
17193b987d70SLad Prabhakar 		/* remain in power down mode for DVP */
17203b987d70SLad Prabhakar 		if (regs->reg_addr == OV5640_REG_SYS_CTRL0 &&
17213b987d70SLad Prabhakar 		    val == OV5640_REG_SYS_CTRL0_SW_PWUP &&
17228e823f5cSJacopo Mondi 		    !ov5640_is_csi2(sensor))
17233b987d70SLad Prabhakar 			continue;
17243b987d70SLad Prabhakar 
172519a81c14SSteve Longerbeam 		if (mask)
172619a81c14SSteve Longerbeam 			ret = ov5640_mod_reg(sensor, reg_addr, mask, val);
172719a81c14SSteve Longerbeam 		else
172819a81c14SSteve Longerbeam 			ret = ov5640_write_reg(sensor, reg_addr, val);
172919a81c14SSteve Longerbeam 		if (ret)
173019a81c14SSteve Longerbeam 			break;
173119a81c14SSteve Longerbeam 
173219a81c14SSteve Longerbeam 		if (delay_ms)
173319a81c14SSteve Longerbeam 			usleep_range(1000 * delay_ms, 1000 * delay_ms + 100);
173419a81c14SSteve Longerbeam 	}
173519a81c14SSteve Longerbeam }
173619a81c14SSteve Longerbeam 
1737dc29a1c1SHugues Fruchet static int ov5640_set_autoexposure(struct ov5640_dev *sensor, bool on)
1738dc29a1c1SHugues Fruchet {
1739dc29a1c1SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
1740dc29a1c1SHugues Fruchet 			      BIT(0), on ? 0 : BIT(0));
1741dc29a1c1SHugues Fruchet }
1742dc29a1c1SHugues Fruchet 
174319a81c14SSteve Longerbeam /* read exposure, in number of line periods */
174419a81c14SSteve Longerbeam static int ov5640_get_exposure(struct ov5640_dev *sensor)
174519a81c14SSteve Longerbeam {
174619a81c14SSteve Longerbeam 	int exp, ret;
174719a81c14SSteve Longerbeam 	u8 temp;
174819a81c14SSteve Longerbeam 
174919a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_HI, &temp);
175019a81c14SSteve Longerbeam 	if (ret)
175119a81c14SSteve Longerbeam 		return ret;
175219a81c14SSteve Longerbeam 	exp = ((int)temp & 0x0f) << 16;
175319a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_MED, &temp);
175419a81c14SSteve Longerbeam 	if (ret)
175519a81c14SSteve Longerbeam 		return ret;
175619a81c14SSteve Longerbeam 	exp |= ((int)temp << 8);
175719a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_LO, &temp);
175819a81c14SSteve Longerbeam 	if (ret)
175919a81c14SSteve Longerbeam 		return ret;
176019a81c14SSteve Longerbeam 	exp |= (int)temp;
176119a81c14SSteve Longerbeam 
176219a81c14SSteve Longerbeam 	return exp >> 4;
176319a81c14SSteve Longerbeam }
176419a81c14SSteve Longerbeam 
176519a81c14SSteve Longerbeam /* write exposure, given number of line periods */
176619a81c14SSteve Longerbeam static int ov5640_set_exposure(struct ov5640_dev *sensor, u32 exposure)
176719a81c14SSteve Longerbeam {
176819a81c14SSteve Longerbeam 	int ret;
176919a81c14SSteve Longerbeam 
177019a81c14SSteve Longerbeam 	exposure <<= 4;
177119a81c14SSteve Longerbeam 
177219a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor,
177319a81c14SSteve Longerbeam 			       OV5640_REG_AEC_PK_EXPOSURE_LO,
177419a81c14SSteve Longerbeam 			       exposure & 0xff);
177519a81c14SSteve Longerbeam 	if (ret)
177619a81c14SSteve Longerbeam 		return ret;
177719a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor,
177819a81c14SSteve Longerbeam 			       OV5640_REG_AEC_PK_EXPOSURE_MED,
177919a81c14SSteve Longerbeam 			       (exposure >> 8) & 0xff);
178019a81c14SSteve Longerbeam 	if (ret)
178119a81c14SSteve Longerbeam 		return ret;
178219a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor,
178319a81c14SSteve Longerbeam 				OV5640_REG_AEC_PK_EXPOSURE_HI,
178419a81c14SSteve Longerbeam 				(exposure >> 16) & 0x0f);
178519a81c14SSteve Longerbeam }
178619a81c14SSteve Longerbeam 
178719a81c14SSteve Longerbeam static int ov5640_get_gain(struct ov5640_dev *sensor)
178819a81c14SSteve Longerbeam {
178919a81c14SSteve Longerbeam 	u16 gain;
179019a81c14SSteve Longerbeam 	int ret;
179119a81c14SSteve Longerbeam 
179219a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN, &gain);
179319a81c14SSteve Longerbeam 	if (ret)
179419a81c14SSteve Longerbeam 		return ret;
179519a81c14SSteve Longerbeam 
179619a81c14SSteve Longerbeam 	return gain & 0x3ff;
179719a81c14SSteve Longerbeam }
179819a81c14SSteve Longerbeam 
17993cca8ef5SHugues Fruchet static int ov5640_set_gain(struct ov5640_dev *sensor, int gain)
18003cca8ef5SHugues Fruchet {
18013cca8ef5SHugues Fruchet 	return ov5640_write_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN,
18023cca8ef5SHugues Fruchet 				  (u16)gain & 0x3ff);
18033cca8ef5SHugues Fruchet }
18043cca8ef5SHugues Fruchet 
18053cca8ef5SHugues Fruchet static int ov5640_set_autogain(struct ov5640_dev *sensor, bool on)
18063cca8ef5SHugues Fruchet {
18073cca8ef5SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
18083cca8ef5SHugues Fruchet 			      BIT(1), on ? 0 : BIT(1));
18093cca8ef5SHugues Fruchet }
18103cca8ef5SHugues Fruchet 
1811f22996dbSHugues Fruchet static int ov5640_set_stream_dvp(struct ov5640_dev *sensor, bool on)
1812f22996dbSHugues Fruchet {
18133b987d70SLad Prabhakar 	return ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0, on ?
18143b987d70SLad Prabhakar 				OV5640_REG_SYS_CTRL0_SW_PWUP :
18153b987d70SLad Prabhakar 				OV5640_REG_SYS_CTRL0_SW_PWDN);
1816f22996dbSHugues Fruchet }
1817f22996dbSHugues Fruchet 
1818f22996dbSHugues Fruchet static int ov5640_set_stream_mipi(struct ov5640_dev *sensor, bool on)
181919a81c14SSteve Longerbeam {
182019a81c14SSteve Longerbeam 	int ret;
182119a81c14SSteve Longerbeam 
1822aa4bb8b8SJacopo Mondi 	/*
1823aa4bb8b8SJacopo Mondi 	 * Enable/disable the MIPI interface
1824aa4bb8b8SJacopo Mondi 	 *
1825aa4bb8b8SJacopo Mondi 	 * 0x300e = on ? 0x45 : 0x40
1826aa4bb8b8SJacopo Mondi 	 *
1827aa4bb8b8SJacopo Mondi 	 * FIXME: the sensor manual (version 2.03) reports
1828aa4bb8b8SJacopo Mondi 	 * [7:5] = 000  : 1 data lane mode
1829aa4bb8b8SJacopo Mondi 	 * [7:5] = 001  : 2 data lanes mode
1830aa4bb8b8SJacopo Mondi 	 * But this settings do not work, while the following ones
1831aa4bb8b8SJacopo Mondi 	 * have been validated for 2 data lanes mode.
1832aa4bb8b8SJacopo Mondi 	 *
1833aa4bb8b8SJacopo Mondi 	 * [7:5] = 010	: 2 data lanes mode
1834aa4bb8b8SJacopo Mondi 	 * [4] = 0	: Power up MIPI HS Tx
1835aa4bb8b8SJacopo Mondi 	 * [3] = 0	: Power up MIPI LS Rx
1836aa4bb8b8SJacopo Mondi 	 * [2] = 1/0	: MIPI interface enable/disable
1837aa4bb8b8SJacopo Mondi 	 * [1:0] = 01/00: FIXME: 'debug'
1838aa4bb8b8SJacopo Mondi 	 */
1839aa4bb8b8SJacopo Mondi 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00,
1840aa4bb8b8SJacopo Mondi 			       on ? 0x45 : 0x40);
184119a81c14SSteve Longerbeam 	if (ret)
184219a81c14SSteve Longerbeam 		return ret;
184319a81c14SSteve Longerbeam 
184419a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_FRAME_CTRL01,
184519a81c14SSteve Longerbeam 				on ? 0x00 : 0x0f);
184619a81c14SSteve Longerbeam }
184719a81c14SSteve Longerbeam 
184819a81c14SSteve Longerbeam static int ov5640_get_sysclk(struct ov5640_dev *sensor)
184919a81c14SSteve Longerbeam {
185019a81c14SSteve Longerbeam 	 /* calculate sysclk */
185119a81c14SSteve Longerbeam 	u32 xvclk = sensor->xclk_freq / 10000;
185219a81c14SSteve Longerbeam 	u32 multiplier, prediv, VCO, sysdiv, pll_rdiv;
185319a81c14SSteve Longerbeam 	u32 sclk_rdiv_map[] = {1, 2, 4, 8};
185419a81c14SSteve Longerbeam 	u32 bit_div2x = 1, sclk_rdiv, sysclk;
185519a81c14SSteve Longerbeam 	u8 temp1, temp2;
185619a81c14SSteve Longerbeam 	int ret;
185719a81c14SSteve Longerbeam 
185819a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL0, &temp1);
185919a81c14SSteve Longerbeam 	if (ret)
186019a81c14SSteve Longerbeam 		return ret;
186119a81c14SSteve Longerbeam 	temp2 = temp1 & 0x0f;
186219a81c14SSteve Longerbeam 	if (temp2 == 8 || temp2 == 10)
186319a81c14SSteve Longerbeam 		bit_div2x = temp2 / 2;
186419a81c14SSteve Longerbeam 
186519a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL1, &temp1);
186619a81c14SSteve Longerbeam 	if (ret)
186719a81c14SSteve Longerbeam 		return ret;
186819a81c14SSteve Longerbeam 	sysdiv = temp1 >> 4;
186919a81c14SSteve Longerbeam 	if (sysdiv == 0)
187019a81c14SSteve Longerbeam 		sysdiv = 16;
187119a81c14SSteve Longerbeam 
187219a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL2, &temp1);
187319a81c14SSteve Longerbeam 	if (ret)
187419a81c14SSteve Longerbeam 		return ret;
187519a81c14SSteve Longerbeam 	multiplier = temp1;
187619a81c14SSteve Longerbeam 
187719a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL3, &temp1);
187819a81c14SSteve Longerbeam 	if (ret)
187919a81c14SSteve Longerbeam 		return ret;
188019a81c14SSteve Longerbeam 	prediv = temp1 & 0x0f;
188119a81c14SSteve Longerbeam 	pll_rdiv = ((temp1 >> 4) & 0x01) + 1;
188219a81c14SSteve Longerbeam 
188319a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, &temp1);
188419a81c14SSteve Longerbeam 	if (ret)
188519a81c14SSteve Longerbeam 		return ret;
188619a81c14SSteve Longerbeam 	temp2 = temp1 & 0x03;
188719a81c14SSteve Longerbeam 	sclk_rdiv = sclk_rdiv_map[temp2];
188819a81c14SSteve Longerbeam 
188919a81c14SSteve Longerbeam 	if (!prediv || !sysdiv || !pll_rdiv || !bit_div2x)
189019a81c14SSteve Longerbeam 		return -EINVAL;
189119a81c14SSteve Longerbeam 
189219a81c14SSteve Longerbeam 	VCO = xvclk * multiplier / prediv;
189319a81c14SSteve Longerbeam 
189419a81c14SSteve Longerbeam 	sysclk = VCO / sysdiv / pll_rdiv * 2 / bit_div2x / sclk_rdiv;
189519a81c14SSteve Longerbeam 
189619a81c14SSteve Longerbeam 	return sysclk;
189719a81c14SSteve Longerbeam }
189819a81c14SSteve Longerbeam 
189919a81c14SSteve Longerbeam static int ov5640_set_night_mode(struct ov5640_dev *sensor)
190019a81c14SSteve Longerbeam {
190119a81c14SSteve Longerbeam 	 /* read HTS from register settings */
190219a81c14SSteve Longerbeam 	u8 mode;
190319a81c14SSteve Longerbeam 	int ret;
190419a81c14SSteve Longerbeam 
190519a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_CTRL00, &mode);
190619a81c14SSteve Longerbeam 	if (ret)
190719a81c14SSteve Longerbeam 		return ret;
190819a81c14SSteve Longerbeam 	mode &= 0xfb;
190919a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL00, mode);
191019a81c14SSteve Longerbeam }
191119a81c14SSteve Longerbeam 
191219a81c14SSteve Longerbeam static int ov5640_get_hts(struct ov5640_dev *sensor)
191319a81c14SSteve Longerbeam {
191419a81c14SSteve Longerbeam 	/* read HTS from register settings */
191519a81c14SSteve Longerbeam 	u16 hts;
191619a81c14SSteve Longerbeam 	int ret;
191719a81c14SSteve Longerbeam 
191819a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_HTS, &hts);
191919a81c14SSteve Longerbeam 	if (ret)
192019a81c14SSteve Longerbeam 		return ret;
192119a81c14SSteve Longerbeam 	return hts;
192219a81c14SSteve Longerbeam }
192319a81c14SSteve Longerbeam 
192419a81c14SSteve Longerbeam static int ov5640_get_vts(struct ov5640_dev *sensor)
192519a81c14SSteve Longerbeam {
192619a81c14SSteve Longerbeam 	u16 vts;
192719a81c14SSteve Longerbeam 	int ret;
192819a81c14SSteve Longerbeam 
192919a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_VTS, &vts);
193019a81c14SSteve Longerbeam 	if (ret)
193119a81c14SSteve Longerbeam 		return ret;
193219a81c14SSteve Longerbeam 	return vts;
193319a81c14SSteve Longerbeam }
193419a81c14SSteve Longerbeam 
193519a81c14SSteve Longerbeam static int ov5640_set_vts(struct ov5640_dev *sensor, int vts)
193619a81c14SSteve Longerbeam {
193719a81c14SSteve Longerbeam 	return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, vts);
193819a81c14SSteve Longerbeam }
193919a81c14SSteve Longerbeam 
194019a81c14SSteve Longerbeam static int ov5640_get_light_freq(struct ov5640_dev *sensor)
194119a81c14SSteve Longerbeam {
194219a81c14SSteve Longerbeam 	/* get banding filter value */
194319a81c14SSteve Longerbeam 	int ret, light_freq = 0;
194419a81c14SSteve Longerbeam 	u8 temp, temp1;
194519a81c14SSteve Longerbeam 
194619a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL01, &temp);
194719a81c14SSteve Longerbeam 	if (ret)
194819a81c14SSteve Longerbeam 		return ret;
194919a81c14SSteve Longerbeam 
195019a81c14SSteve Longerbeam 	if (temp & 0x80) {
195119a81c14SSteve Longerbeam 		/* manual */
195219a81c14SSteve Longerbeam 		ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL00,
195319a81c14SSteve Longerbeam 				      &temp1);
195419a81c14SSteve Longerbeam 		if (ret)
195519a81c14SSteve Longerbeam 			return ret;
195619a81c14SSteve Longerbeam 		if (temp1 & 0x04) {
195719a81c14SSteve Longerbeam 			/* 50Hz */
195819a81c14SSteve Longerbeam 			light_freq = 50;
195919a81c14SSteve Longerbeam 		} else {
196019a81c14SSteve Longerbeam 			/* 60Hz */
196119a81c14SSteve Longerbeam 			light_freq = 60;
196219a81c14SSteve Longerbeam 		}
196319a81c14SSteve Longerbeam 	} else {
196419a81c14SSteve Longerbeam 		/* auto */
196519a81c14SSteve Longerbeam 		ret = ov5640_read_reg(sensor, OV5640_REG_SIGMADELTA_CTRL0C,
196619a81c14SSteve Longerbeam 				      &temp1);
196719a81c14SSteve Longerbeam 		if (ret)
196819a81c14SSteve Longerbeam 			return ret;
196919a81c14SSteve Longerbeam 
197019a81c14SSteve Longerbeam 		if (temp1 & 0x01) {
197119a81c14SSteve Longerbeam 			/* 50Hz */
197219a81c14SSteve Longerbeam 			light_freq = 50;
197319a81c14SSteve Longerbeam 		} else {
197419a81c14SSteve Longerbeam 			/* 60Hz */
197519a81c14SSteve Longerbeam 		}
197619a81c14SSteve Longerbeam 	}
197719a81c14SSteve Longerbeam 
197819a81c14SSteve Longerbeam 	return light_freq;
197919a81c14SSteve Longerbeam }
198019a81c14SSteve Longerbeam 
198119a81c14SSteve Longerbeam static int ov5640_set_bandingfilter(struct ov5640_dev *sensor)
198219a81c14SSteve Longerbeam {
198319a81c14SSteve Longerbeam 	u32 band_step60, max_band60, band_step50, max_band50, prev_vts;
198419a81c14SSteve Longerbeam 	int ret;
198519a81c14SSteve Longerbeam 
198619a81c14SSteve Longerbeam 	/* read preview PCLK */
198719a81c14SSteve Longerbeam 	ret = ov5640_get_sysclk(sensor);
198819a81c14SSteve Longerbeam 	if (ret < 0)
198919a81c14SSteve Longerbeam 		return ret;
199019a81c14SSteve Longerbeam 	if (ret == 0)
199119a81c14SSteve Longerbeam 		return -EINVAL;
199219a81c14SSteve Longerbeam 	sensor->prev_sysclk = ret;
199319a81c14SSteve Longerbeam 	/* read preview HTS */
199419a81c14SSteve Longerbeam 	ret = ov5640_get_hts(sensor);
199519a81c14SSteve Longerbeam 	if (ret < 0)
199619a81c14SSteve Longerbeam 		return ret;
199719a81c14SSteve Longerbeam 	if (ret == 0)
199819a81c14SSteve Longerbeam 		return -EINVAL;
199919a81c14SSteve Longerbeam 	sensor->prev_hts = ret;
200019a81c14SSteve Longerbeam 
200119a81c14SSteve Longerbeam 	/* read preview VTS */
200219a81c14SSteve Longerbeam 	ret = ov5640_get_vts(sensor);
200319a81c14SSteve Longerbeam 	if (ret < 0)
200419a81c14SSteve Longerbeam 		return ret;
200519a81c14SSteve Longerbeam 	prev_vts = ret;
200619a81c14SSteve Longerbeam 
200719a81c14SSteve Longerbeam 	/* calculate banding filter */
200819a81c14SSteve Longerbeam 	/* 60Hz */
200919a81c14SSteve Longerbeam 	band_step60 = sensor->prev_sysclk * 100 / sensor->prev_hts * 100 / 120;
201019a81c14SSteve Longerbeam 	ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B60_STEP, band_step60);
201119a81c14SSteve Longerbeam 	if (ret)
201219a81c14SSteve Longerbeam 		return ret;
201319a81c14SSteve Longerbeam 	if (!band_step60)
201419a81c14SSteve Longerbeam 		return -EINVAL;
201519a81c14SSteve Longerbeam 	max_band60 = (int)((prev_vts - 4) / band_step60);
201619a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0D, max_band60);
201719a81c14SSteve Longerbeam 	if (ret)
201819a81c14SSteve Longerbeam 		return ret;
201919a81c14SSteve Longerbeam 
202019a81c14SSteve Longerbeam 	/* 50Hz */
202119a81c14SSteve Longerbeam 	band_step50 = sensor->prev_sysclk * 100 / sensor->prev_hts;
202219a81c14SSteve Longerbeam 	ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B50_STEP, band_step50);
202319a81c14SSteve Longerbeam 	if (ret)
202419a81c14SSteve Longerbeam 		return ret;
202519a81c14SSteve Longerbeam 	if (!band_step50)
202619a81c14SSteve Longerbeam 		return -EINVAL;
202719a81c14SSteve Longerbeam 	max_band50 = (int)((prev_vts - 4) / band_step50);
202819a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0E, max_band50);
202919a81c14SSteve Longerbeam }
203019a81c14SSteve Longerbeam 
203119a81c14SSteve Longerbeam static int ov5640_set_ae_target(struct ov5640_dev *sensor, int target)
203219a81c14SSteve Longerbeam {
203319a81c14SSteve Longerbeam 	/* stable in high */
203419a81c14SSteve Longerbeam 	u32 fast_high, fast_low;
203519a81c14SSteve Longerbeam 	int ret;
203619a81c14SSteve Longerbeam 
203719a81c14SSteve Longerbeam 	sensor->ae_low = target * 23 / 25;	/* 0.92 */
203819a81c14SSteve Longerbeam 	sensor->ae_high = target * 27 / 25;	/* 1.08 */
203919a81c14SSteve Longerbeam 
204019a81c14SSteve Longerbeam 	fast_high = sensor->ae_high << 1;
204119a81c14SSteve Longerbeam 	if (fast_high > 255)
204219a81c14SSteve Longerbeam 		fast_high = 255;
204319a81c14SSteve Longerbeam 
204419a81c14SSteve Longerbeam 	fast_low = sensor->ae_low >> 1;
204519a81c14SSteve Longerbeam 
204619a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0F, sensor->ae_high);
204719a81c14SSteve Longerbeam 	if (ret)
204819a81c14SSteve Longerbeam 		return ret;
204919a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL10, sensor->ae_low);
205019a81c14SSteve Longerbeam 	if (ret)
205119a81c14SSteve Longerbeam 		return ret;
205219a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1B, sensor->ae_high);
205319a81c14SSteve Longerbeam 	if (ret)
205419a81c14SSteve Longerbeam 		return ret;
205519a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1E, sensor->ae_low);
205619a81c14SSteve Longerbeam 	if (ret)
205719a81c14SSteve Longerbeam 		return ret;
205819a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL11, fast_high);
205919a81c14SSteve Longerbeam 	if (ret)
206019a81c14SSteve Longerbeam 		return ret;
206119a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1F, fast_low);
206219a81c14SSteve Longerbeam }
206319a81c14SSteve Longerbeam 
2064c2c3f42dSHugues Fruchet static int ov5640_get_binning(struct ov5640_dev *sensor)
206519a81c14SSteve Longerbeam {
206619a81c14SSteve Longerbeam 	u8 temp;
206719a81c14SSteve Longerbeam 	int ret;
206819a81c14SSteve Longerbeam 
206919a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_TIMING_TC_REG21, &temp);
207019a81c14SSteve Longerbeam 	if (ret)
207119a81c14SSteve Longerbeam 		return ret;
2072c2c3f42dSHugues Fruchet 
2073c2c3f42dSHugues Fruchet 	return temp & BIT(0);
207419a81c14SSteve Longerbeam }
207519a81c14SSteve Longerbeam 
2076ce85705aSHugues Fruchet static int ov5640_set_binning(struct ov5640_dev *sensor, bool enable)
2077ce85705aSHugues Fruchet {
2078ce85705aSHugues Fruchet 	int ret;
2079ce85705aSHugues Fruchet 
2080ce85705aSHugues Fruchet 	/*
2081ce85705aSHugues Fruchet 	 * TIMING TC REG21:
2082ce85705aSHugues Fruchet 	 * - [0]:	Horizontal binning enable
2083ce85705aSHugues Fruchet 	 */
2084ce85705aSHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
2085ce85705aSHugues Fruchet 			     BIT(0), enable ? BIT(0) : 0);
2086ce85705aSHugues Fruchet 	if (ret)
2087ce85705aSHugues Fruchet 		return ret;
2088ce85705aSHugues Fruchet 	/*
2089ce85705aSHugues Fruchet 	 * TIMING TC REG20:
2090ce85705aSHugues Fruchet 	 * - [0]:	Undocumented, but hardcoded init sequences
2091ce85705aSHugues Fruchet 	 *		are always setting REG21/REG20 bit 0 to same value...
2092ce85705aSHugues Fruchet 	 */
2093ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20,
2094ce85705aSHugues Fruchet 			      BIT(0), enable ? BIT(0) : 0);
2095ce85705aSHugues Fruchet }
2096ce85705aSHugues Fruchet 
209719a81c14SSteve Longerbeam static int ov5640_set_virtual_channel(struct ov5640_dev *sensor)
209819a81c14SSteve Longerbeam {
20998670d70aSHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
210019a81c14SSteve Longerbeam 	u8 temp, channel = virtual_channel;
210119a81c14SSteve Longerbeam 	int ret;
210219a81c14SSteve Longerbeam 
21038670d70aSHugues Fruchet 	if (channel > 3) {
21048670d70aSHugues Fruchet 		dev_err(&client->dev,
21058670d70aSHugues Fruchet 			"%s: wrong virtual_channel parameter, expected (0..3), got %d\n",
21068670d70aSHugues Fruchet 			__func__, channel);
210719a81c14SSteve Longerbeam 		return -EINVAL;
21088670d70aSHugues Fruchet 	}
210919a81c14SSteve Longerbeam 
211019a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_DEBUG_MODE, &temp);
211119a81c14SSteve Longerbeam 	if (ret)
211219a81c14SSteve Longerbeam 		return ret;
211319a81c14SSteve Longerbeam 	temp &= ~(3 << 6);
211419a81c14SSteve Longerbeam 	temp |= (channel << 6);
211519a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_DEBUG_MODE, temp);
211619a81c14SSteve Longerbeam }
211719a81c14SSteve Longerbeam 
211819a81c14SSteve Longerbeam static const struct ov5640_mode_info *
2119b6ae5022SJacopo Mondi ov5640_find_mode(struct ov5640_dev *sensor, int width, int height, bool nearest)
212019a81c14SSteve Longerbeam {
21213c4a7372SHugues Fruchet 	const struct ov5640_mode_info *mode;
212219a81c14SSteve Longerbeam 
2123086c25f8SMaxime Ripard 	mode = v4l2_find_nearest_size(ov5640_mode_data,
2124086c25f8SMaxime Ripard 				      ARRAY_SIZE(ov5640_mode_data),
21255113d5b3SJacopo Mondi 				      width, height, width, height);
212619a81c14SSteve Longerbeam 
21273c4a7372SHugues Fruchet 	if (!mode ||
21283145efcdSJacopo Mondi 	    (!nearest &&
21295113d5b3SJacopo Mondi 	     (mode->width != width || mode->height != height)))
21303c4a7372SHugues Fruchet 		return NULL;
213119a81c14SSteve Longerbeam 
213219a81c14SSteve Longerbeam 	return mode;
213319a81c14SSteve Longerbeam }
213419a81c14SSteve Longerbeam 
213519a81c14SSteve Longerbeam /*
213619a81c14SSteve Longerbeam  * sensor changes between scaling and subsampling, go through
213719a81c14SSteve Longerbeam  * exposure calculation
213819a81c14SSteve Longerbeam  */
213941d8d7f5SHugues Fruchet static int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor,
214041d8d7f5SHugues Fruchet 					 const struct ov5640_mode_info *mode)
214119a81c14SSteve Longerbeam {
214219a81c14SSteve Longerbeam 	u32 prev_shutter, prev_gain16;
214319a81c14SSteve Longerbeam 	u32 cap_shutter, cap_gain16;
214419a81c14SSteve Longerbeam 	u32 cap_sysclk, cap_hts, cap_vts;
214519a81c14SSteve Longerbeam 	u32 light_freq, cap_bandfilt, cap_maxband;
214619a81c14SSteve Longerbeam 	u32 cap_gain16_shutter;
214719a81c14SSteve Longerbeam 	u8 average;
214819a81c14SSteve Longerbeam 	int ret;
214919a81c14SSteve Longerbeam 
215041d8d7f5SHugues Fruchet 	if (!mode->reg_data)
215119a81c14SSteve Longerbeam 		return -EINVAL;
215219a81c14SSteve Longerbeam 
215319a81c14SSteve Longerbeam 	/* read preview shutter */
215419a81c14SSteve Longerbeam 	ret = ov5640_get_exposure(sensor);
215519a81c14SSteve Longerbeam 	if (ret < 0)
215619a81c14SSteve Longerbeam 		return ret;
215719a81c14SSteve Longerbeam 	prev_shutter = ret;
2158c2c3f42dSHugues Fruchet 	ret = ov5640_get_binning(sensor);
215919a81c14SSteve Longerbeam 	if (ret < 0)
216019a81c14SSteve Longerbeam 		return ret;
216119a81c14SSteve Longerbeam 	if (ret && mode->id != OV5640_MODE_720P_1280_720 &&
216219a81c14SSteve Longerbeam 	    mode->id != OV5640_MODE_1080P_1920_1080)
216319a81c14SSteve Longerbeam 		prev_shutter *= 2;
216419a81c14SSteve Longerbeam 
216519a81c14SSteve Longerbeam 	/* read preview gain */
216619a81c14SSteve Longerbeam 	ret = ov5640_get_gain(sensor);
216719a81c14SSteve Longerbeam 	if (ret < 0)
216819a81c14SSteve Longerbeam 		return ret;
216919a81c14SSteve Longerbeam 	prev_gain16 = ret;
217019a81c14SSteve Longerbeam 
217119a81c14SSteve Longerbeam 	/* get average */
217219a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AVG_READOUT, &average);
217319a81c14SSteve Longerbeam 	if (ret)
217419a81c14SSteve Longerbeam 		return ret;
217519a81c14SSteve Longerbeam 
217619a81c14SSteve Longerbeam 	/* turn off night mode for capture */
217719a81c14SSteve Longerbeam 	ret = ov5640_set_night_mode(sensor);
217819a81c14SSteve Longerbeam 	if (ret < 0)
217919a81c14SSteve Longerbeam 		return ret;
218019a81c14SSteve Longerbeam 
218119a81c14SSteve Longerbeam 	/* Write capture setting */
2182e4359019SJacopo Mondi 	ov5640_load_regs(sensor, mode->reg_data, mode->reg_data_size);
2183e4359019SJacopo Mondi 	ret = ov5640_set_timings(sensor, mode);
218419a81c14SSteve Longerbeam 	if (ret < 0)
218519a81c14SSteve Longerbeam 		return ret;
218619a81c14SSteve Longerbeam 
218719a81c14SSteve Longerbeam 	/* read capture VTS */
218819a81c14SSteve Longerbeam 	ret = ov5640_get_vts(sensor);
218919a81c14SSteve Longerbeam 	if (ret < 0)
219019a81c14SSteve Longerbeam 		return ret;
219119a81c14SSteve Longerbeam 	cap_vts = ret;
219219a81c14SSteve Longerbeam 	ret = ov5640_get_hts(sensor);
219319a81c14SSteve Longerbeam 	if (ret < 0)
219419a81c14SSteve Longerbeam 		return ret;
219519a81c14SSteve Longerbeam 	if (ret == 0)
219619a81c14SSteve Longerbeam 		return -EINVAL;
219719a81c14SSteve Longerbeam 	cap_hts = ret;
219819a81c14SSteve Longerbeam 
219919a81c14SSteve Longerbeam 	ret = ov5640_get_sysclk(sensor);
220019a81c14SSteve Longerbeam 	if (ret < 0)
220119a81c14SSteve Longerbeam 		return ret;
220219a81c14SSteve Longerbeam 	if (ret == 0)
220319a81c14SSteve Longerbeam 		return -EINVAL;
220419a81c14SSteve Longerbeam 	cap_sysclk = ret;
220519a81c14SSteve Longerbeam 
220619a81c14SSteve Longerbeam 	/* calculate capture banding filter */
220719a81c14SSteve Longerbeam 	ret = ov5640_get_light_freq(sensor);
220819a81c14SSteve Longerbeam 	if (ret < 0)
220919a81c14SSteve Longerbeam 		return ret;
221019a81c14SSteve Longerbeam 	light_freq = ret;
221119a81c14SSteve Longerbeam 
221219a81c14SSteve Longerbeam 	if (light_freq == 60) {
221319a81c14SSteve Longerbeam 		/* 60Hz */
221419a81c14SSteve Longerbeam 		cap_bandfilt = cap_sysclk * 100 / cap_hts * 100 / 120;
221519a81c14SSteve Longerbeam 	} else {
221619a81c14SSteve Longerbeam 		/* 50Hz */
221719a81c14SSteve Longerbeam 		cap_bandfilt = cap_sysclk * 100 / cap_hts;
221819a81c14SSteve Longerbeam 	}
221919a81c14SSteve Longerbeam 
222019a81c14SSteve Longerbeam 	if (!sensor->prev_sysclk) {
222119a81c14SSteve Longerbeam 		ret = ov5640_get_sysclk(sensor);
222219a81c14SSteve Longerbeam 		if (ret < 0)
222319a81c14SSteve Longerbeam 			return ret;
222419a81c14SSteve Longerbeam 		if (ret == 0)
222519a81c14SSteve Longerbeam 			return -EINVAL;
222619a81c14SSteve Longerbeam 		sensor->prev_sysclk = ret;
222719a81c14SSteve Longerbeam 	}
222819a81c14SSteve Longerbeam 
222919a81c14SSteve Longerbeam 	if (!cap_bandfilt)
223019a81c14SSteve Longerbeam 		return -EINVAL;
223119a81c14SSteve Longerbeam 
223219a81c14SSteve Longerbeam 	cap_maxband = (int)((cap_vts - 4) / cap_bandfilt);
223319a81c14SSteve Longerbeam 
223419a81c14SSteve Longerbeam 	/* calculate capture shutter/gain16 */
223519a81c14SSteve Longerbeam 	if (average > sensor->ae_low && average < sensor->ae_high) {
223619a81c14SSteve Longerbeam 		/* in stable range */
223719a81c14SSteve Longerbeam 		cap_gain16_shutter =
223819a81c14SSteve Longerbeam 			prev_gain16 * prev_shutter *
223919a81c14SSteve Longerbeam 			cap_sysclk / sensor->prev_sysclk *
224019a81c14SSteve Longerbeam 			sensor->prev_hts / cap_hts *
224119a81c14SSteve Longerbeam 			sensor->ae_target / average;
224219a81c14SSteve Longerbeam 	} else {
224319a81c14SSteve Longerbeam 		cap_gain16_shutter =
224419a81c14SSteve Longerbeam 			prev_gain16 * prev_shutter *
224519a81c14SSteve Longerbeam 			cap_sysclk / sensor->prev_sysclk *
224619a81c14SSteve Longerbeam 			sensor->prev_hts / cap_hts;
224719a81c14SSteve Longerbeam 	}
224819a81c14SSteve Longerbeam 
224919a81c14SSteve Longerbeam 	/* gain to shutter */
225019a81c14SSteve Longerbeam 	if (cap_gain16_shutter < (cap_bandfilt * 16)) {
225119a81c14SSteve Longerbeam 		/* shutter < 1/100 */
225219a81c14SSteve Longerbeam 		cap_shutter = cap_gain16_shutter / 16;
225319a81c14SSteve Longerbeam 		if (cap_shutter < 1)
225419a81c14SSteve Longerbeam 			cap_shutter = 1;
225519a81c14SSteve Longerbeam 
225619a81c14SSteve Longerbeam 		cap_gain16 = cap_gain16_shutter / cap_shutter;
225719a81c14SSteve Longerbeam 		if (cap_gain16 < 16)
225819a81c14SSteve Longerbeam 			cap_gain16 = 16;
225919a81c14SSteve Longerbeam 	} else {
226019a81c14SSteve Longerbeam 		if (cap_gain16_shutter > (cap_bandfilt * cap_maxband * 16)) {
226119a81c14SSteve Longerbeam 			/* exposure reach max */
226219a81c14SSteve Longerbeam 			cap_shutter = cap_bandfilt * cap_maxband;
226319a81c14SSteve Longerbeam 			if (!cap_shutter)
226419a81c14SSteve Longerbeam 				return -EINVAL;
226519a81c14SSteve Longerbeam 
226619a81c14SSteve Longerbeam 			cap_gain16 = cap_gain16_shutter / cap_shutter;
226719a81c14SSteve Longerbeam 		} else {
226819a81c14SSteve Longerbeam 			/* 1/100 < (cap_shutter = n/100) =< max */
226919a81c14SSteve Longerbeam 			cap_shutter =
227019a81c14SSteve Longerbeam 				((int)(cap_gain16_shutter / 16 / cap_bandfilt))
227119a81c14SSteve Longerbeam 				* cap_bandfilt;
227219a81c14SSteve Longerbeam 			if (!cap_shutter)
227319a81c14SSteve Longerbeam 				return -EINVAL;
227419a81c14SSteve Longerbeam 
227519a81c14SSteve Longerbeam 			cap_gain16 = cap_gain16_shutter / cap_shutter;
227619a81c14SSteve Longerbeam 		}
227719a81c14SSteve Longerbeam 	}
227819a81c14SSteve Longerbeam 
227919a81c14SSteve Longerbeam 	/* set capture gain */
22803cca8ef5SHugues Fruchet 	ret = ov5640_set_gain(sensor, cap_gain16);
228119a81c14SSteve Longerbeam 	if (ret)
228219a81c14SSteve Longerbeam 		return ret;
228319a81c14SSteve Longerbeam 
228419a81c14SSteve Longerbeam 	/* write capture shutter */
228519a81c14SSteve Longerbeam 	if (cap_shutter > (cap_vts - 4)) {
228619a81c14SSteve Longerbeam 		cap_vts = cap_shutter + 4;
228719a81c14SSteve Longerbeam 		ret = ov5640_set_vts(sensor, cap_vts);
228819a81c14SSteve Longerbeam 		if (ret < 0)
228919a81c14SSteve Longerbeam 			return ret;
229019a81c14SSteve Longerbeam 	}
229119a81c14SSteve Longerbeam 
229219a81c14SSteve Longerbeam 	/* set exposure */
22933cca8ef5SHugues Fruchet 	return ov5640_set_exposure(sensor, cap_shutter);
229419a81c14SSteve Longerbeam }
229519a81c14SSteve Longerbeam 
229619a81c14SSteve Longerbeam /*
229719a81c14SSteve Longerbeam  * if sensor changes inside scaling or subsampling
229819a81c14SSteve Longerbeam  * change mode directly
229919a81c14SSteve Longerbeam  */
230019a81c14SSteve Longerbeam static int ov5640_set_mode_direct(struct ov5640_dev *sensor,
23013cca8ef5SHugues Fruchet 				  const struct ov5640_mode_info *mode)
230219a81c14SSteve Longerbeam {
230341d8d7f5SHugues Fruchet 	if (!mode->reg_data)
230419a81c14SSteve Longerbeam 		return -EINVAL;
230519a81c14SSteve Longerbeam 
230619a81c14SSteve Longerbeam 	/* Write capture setting */
2307e4359019SJacopo Mondi 	ov5640_load_regs(sensor, mode->reg_data, mode->reg_data_size);
2308e4359019SJacopo Mondi 	return ov5640_set_timings(sensor, mode);
230919a81c14SSteve Longerbeam }
231019a81c14SSteve Longerbeam 
2311985cdcb0SHugues Fruchet static int ov5640_set_mode(struct ov5640_dev *sensor)
231219a81c14SSteve Longerbeam {
231319a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode = sensor->current_mode;
2314985cdcb0SHugues Fruchet 	const struct ov5640_mode_info *orig_mode = sensor->last_mode;
231519a81c14SSteve Longerbeam 	enum ov5640_downsize_mode dn_mode, orig_dn_mode;
23163cca8ef5SHugues Fruchet 	bool auto_gain = sensor->ctrls.auto_gain->val == 1;
2317dc29a1c1SHugues Fruchet 	bool auto_exp =  sensor->ctrls.auto_exp->val == V4L2_EXPOSURE_AUTO;
231819a81c14SSteve Longerbeam 	int ret;
231919a81c14SSteve Longerbeam 
232019a81c14SSteve Longerbeam 	dn_mode = mode->dn_mode;
232119a81c14SSteve Longerbeam 	orig_dn_mode = orig_mode->dn_mode;
232219a81c14SSteve Longerbeam 
232319a81c14SSteve Longerbeam 	/* auto gain and exposure must be turned off when changing modes */
23243cca8ef5SHugues Fruchet 	if (auto_gain) {
23253cca8ef5SHugues Fruchet 		ret = ov5640_set_autogain(sensor, false);
232619a81c14SSteve Longerbeam 		if (ret)
232719a81c14SSteve Longerbeam 			return ret;
23283cca8ef5SHugues Fruchet 	}
2329bf4a4b51SMaxime Ripard 
23303cca8ef5SHugues Fruchet 	if (auto_exp) {
2331dc29a1c1SHugues Fruchet 		ret = ov5640_set_autoexposure(sensor, false);
233219a81c14SSteve Longerbeam 		if (ret)
23333cca8ef5SHugues Fruchet 			goto restore_auto_gain;
23343cca8ef5SHugues Fruchet 	}
233519a81c14SSteve Longerbeam 
23366c957ed7SJacopo Mondi 	if (ov5640_is_csi2(sensor))
23376c957ed7SJacopo Mondi 		ret = ov5640_set_mipi_pclk(sensor);
23386c957ed7SJacopo Mondi 	else
23396c957ed7SJacopo Mondi 		ret = ov5640_set_dvp_pclk(sensor);
2340aa288248SMaxime Ripard 	if (ret < 0)
2341aa288248SMaxime Ripard 		return 0;
2342aa288248SMaxime Ripard 
234319a81c14SSteve Longerbeam 	if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) ||
234419a81c14SSteve Longerbeam 	    (dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) {
234519a81c14SSteve Longerbeam 		/*
234619a81c14SSteve Longerbeam 		 * change between subsampling and scaling
23473cca8ef5SHugues Fruchet 		 * go through exposure calculation
234819a81c14SSteve Longerbeam 		 */
234919a81c14SSteve Longerbeam 		ret = ov5640_set_mode_exposure_calc(sensor, mode);
235019a81c14SSteve Longerbeam 	} else {
235119a81c14SSteve Longerbeam 		/*
235219a81c14SSteve Longerbeam 		 * change inside subsampling or scaling
235319a81c14SSteve Longerbeam 		 * download firmware directly
235419a81c14SSteve Longerbeam 		 */
23553cca8ef5SHugues Fruchet 		ret = ov5640_set_mode_direct(sensor, mode);
235619a81c14SSteve Longerbeam 	}
235719a81c14SSteve Longerbeam 	if (ret < 0)
23583cca8ef5SHugues Fruchet 		goto restore_auto_exp_gain;
23593cca8ef5SHugues Fruchet 
23603cca8ef5SHugues Fruchet 	/* restore auto gain and exposure */
23613cca8ef5SHugues Fruchet 	if (auto_gain)
23623cca8ef5SHugues Fruchet 		ov5640_set_autogain(sensor, true);
23633cca8ef5SHugues Fruchet 	if (auto_exp)
23643cca8ef5SHugues Fruchet 		ov5640_set_autoexposure(sensor, true);
236519a81c14SSteve Longerbeam 
2366ce85705aSHugues Fruchet 	ret = ov5640_set_binning(sensor, dn_mode != SCALING);
2367ce85705aSHugues Fruchet 	if (ret < 0)
2368ce85705aSHugues Fruchet 		return ret;
236919a81c14SSteve Longerbeam 	ret = ov5640_set_ae_target(sensor, sensor->ae_target);
237019a81c14SSteve Longerbeam 	if (ret < 0)
237119a81c14SSteve Longerbeam 		return ret;
237219a81c14SSteve Longerbeam 	ret = ov5640_get_light_freq(sensor);
237319a81c14SSteve Longerbeam 	if (ret < 0)
237419a81c14SSteve Longerbeam 		return ret;
237519a81c14SSteve Longerbeam 	ret = ov5640_set_bandingfilter(sensor);
237619a81c14SSteve Longerbeam 	if (ret < 0)
237719a81c14SSteve Longerbeam 		return ret;
237819a81c14SSteve Longerbeam 	ret = ov5640_set_virtual_channel(sensor);
237919a81c14SSteve Longerbeam 	if (ret < 0)
238019a81c14SSteve Longerbeam 		return ret;
238119a81c14SSteve Longerbeam 
238219a81c14SSteve Longerbeam 	sensor->pending_mode_change = false;
2383985cdcb0SHugues Fruchet 	sensor->last_mode = mode;
238419a81c14SSteve Longerbeam 
238519a81c14SSteve Longerbeam 	return 0;
23863cca8ef5SHugues Fruchet 
23873cca8ef5SHugues Fruchet restore_auto_exp_gain:
23883cca8ef5SHugues Fruchet 	if (auto_exp)
23893cca8ef5SHugues Fruchet 		ov5640_set_autoexposure(sensor, true);
23903cca8ef5SHugues Fruchet restore_auto_gain:
23913cca8ef5SHugues Fruchet 	if (auto_gain)
23923cca8ef5SHugues Fruchet 		ov5640_set_autogain(sensor, true);
23933cca8ef5SHugues Fruchet 
23943cca8ef5SHugues Fruchet 	return ret;
239519a81c14SSteve Longerbeam }
239619a81c14SSteve Longerbeam 
239719ad26f9SAkinobu Mita static int ov5640_set_framefmt(struct ov5640_dev *sensor,
239819ad26f9SAkinobu Mita 			       struct v4l2_mbus_framefmt *format);
239919ad26f9SAkinobu Mita 
240019a81c14SSteve Longerbeam /* restore the last set video mode after chip power-on */
240119a81c14SSteve Longerbeam static int ov5640_restore_mode(struct ov5640_dev *sensor)
240219a81c14SSteve Longerbeam {
240319a81c14SSteve Longerbeam 	int ret;
240419a81c14SSteve Longerbeam 
240519a81c14SSteve Longerbeam 	/* first load the initial register values */
2406e4359019SJacopo Mondi 	ov5640_load_regs(sensor, ov5640_init_setting,
2407e4359019SJacopo Mondi 			 ARRAY_SIZE(ov5640_init_setting));
240819a81c14SSteve Longerbeam 
24098f57c2f8SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
24107851fe7aSMaxime Ripard 			     (ilog2(OV5640_SCLK2X_ROOT_DIV) << 2) |
24117851fe7aSMaxime Ripard 			     ilog2(OV5640_SCLK_ROOT_DIV));
24128f57c2f8SMaxime Ripard 	if (ret)
24138f57c2f8SMaxime Ripard 		return ret;
24148f57c2f8SMaxime Ripard 
241519a81c14SSteve Longerbeam 	/* now restore the last capture mode */
2416985cdcb0SHugues Fruchet 	ret = ov5640_set_mode(sensor);
241719ad26f9SAkinobu Mita 	if (ret < 0)
241819ad26f9SAkinobu Mita 		return ret;
241919ad26f9SAkinobu Mita 
242019ad26f9SAkinobu Mita 	return ov5640_set_framefmt(sensor, &sensor->fmt);
242119a81c14SSteve Longerbeam }
242219a81c14SSteve Longerbeam 
242319a81c14SSteve Longerbeam static void ov5640_power(struct ov5640_dev *sensor, bool enable)
242419a81c14SSteve Longerbeam {
24251fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->pwdn_gpio, enable ? 0 : 1);
242619a81c14SSteve Longerbeam }
242719a81c14SSteve Longerbeam 
242819a81c14SSteve Longerbeam static void ov5640_reset(struct ov5640_dev *sensor)
242919a81c14SSteve Longerbeam {
243019a81c14SSteve Longerbeam 	if (!sensor->reset_gpio)
243119a81c14SSteve Longerbeam 		return;
243219a81c14SSteve Longerbeam 
24331fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 0);
243419a81c14SSteve Longerbeam 
243519a81c14SSteve Longerbeam 	/* camera power cycle */
243619a81c14SSteve Longerbeam 	ov5640_power(sensor, false);
243719a81c14SSteve Longerbeam 	usleep_range(5000, 10000);
243819a81c14SSteve Longerbeam 	ov5640_power(sensor, true);
243919a81c14SSteve Longerbeam 	usleep_range(5000, 10000);
244019a81c14SSteve Longerbeam 
24411fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 1);
244219a81c14SSteve Longerbeam 	usleep_range(1000, 2000);
244319a81c14SSteve Longerbeam 
24441fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 0);
24451d4c41f3SLoic Poulain 	usleep_range(20000, 25000);
244619a81c14SSteve Longerbeam }
244719a81c14SSteve Longerbeam 
24480f7acb52SHugues Fruchet static int ov5640_set_power_on(struct ov5640_dev *sensor)
244919a81c14SSteve Longerbeam {
24500f7acb52SHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
24510f7acb52SHugues Fruchet 	int ret;
245219a81c14SSteve Longerbeam 
24530f7acb52SHugues Fruchet 	ret = clk_prepare_enable(sensor->xclk);
24540f7acb52SHugues Fruchet 	if (ret) {
24550f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to enable clock\n",
24560f7acb52SHugues Fruchet 			__func__);
24570f7acb52SHugues Fruchet 		return ret;
24580f7acb52SHugues Fruchet 	}
245919a81c14SSteve Longerbeam 
246019a81c14SSteve Longerbeam 	ret = regulator_bulk_enable(OV5640_NUM_SUPPLIES,
246119a81c14SSteve Longerbeam 				    sensor->supplies);
24620f7acb52SHugues Fruchet 	if (ret) {
24630f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to enable regulators\n",
24640f7acb52SHugues Fruchet 			__func__);
246519a81c14SSteve Longerbeam 		goto xclk_off;
24660f7acb52SHugues Fruchet 	}
246719a81c14SSteve Longerbeam 
246819a81c14SSteve Longerbeam 	ov5640_reset(sensor);
246919a81c14SSteve Longerbeam 	ov5640_power(sensor, true);
247019a81c14SSteve Longerbeam 
247119a81c14SSteve Longerbeam 	ret = ov5640_init_slave_id(sensor);
247219a81c14SSteve Longerbeam 	if (ret)
247319a81c14SSteve Longerbeam 		goto power_off;
247419a81c14SSteve Longerbeam 
24750f7acb52SHugues Fruchet 	return 0;
24760f7acb52SHugues Fruchet 
24770f7acb52SHugues Fruchet power_off:
24780f7acb52SHugues Fruchet 	ov5640_power(sensor, false);
24790f7acb52SHugues Fruchet 	regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies);
24800f7acb52SHugues Fruchet xclk_off:
24810f7acb52SHugues Fruchet 	clk_disable_unprepare(sensor->xclk);
24820f7acb52SHugues Fruchet 	return ret;
24830f7acb52SHugues Fruchet }
24840f7acb52SHugues Fruchet 
24850f7acb52SHugues Fruchet static void ov5640_set_power_off(struct ov5640_dev *sensor)
24860f7acb52SHugues Fruchet {
24870f7acb52SHugues Fruchet 	ov5640_power(sensor, false);
24880f7acb52SHugues Fruchet 	regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies);
24890f7acb52SHugues Fruchet 	clk_disable_unprepare(sensor->xclk);
24900f7acb52SHugues Fruchet }
24910f7acb52SHugues Fruchet 
2492b1751ae6SLad Prabhakar static int ov5640_set_power_mipi(struct ov5640_dev *sensor, bool on)
2493b1751ae6SLad Prabhakar {
2494b1751ae6SLad Prabhakar 	int ret;
2495b1751ae6SLad Prabhakar 
2496b1751ae6SLad Prabhakar 	if (!on) {
2497b1751ae6SLad Prabhakar 		/* Reset MIPI bus settings to their default values. */
2498b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
2499b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x04);
2500b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x00);
2501b1751ae6SLad Prabhakar 		return 0;
2502b1751ae6SLad Prabhakar 	}
2503b1751ae6SLad Prabhakar 
2504b1751ae6SLad Prabhakar 	/*
2505b1751ae6SLad Prabhakar 	 * Power up MIPI HS Tx and LS Rx; 2 data lanes mode
2506b1751ae6SLad Prabhakar 	 *
2507b1751ae6SLad Prabhakar 	 * 0x300e = 0x40
2508b1751ae6SLad Prabhakar 	 * [7:5] = 010	: 2 data lanes mode (see FIXME note in
2509b1751ae6SLad Prabhakar 	 *		  "ov5640_set_stream_mipi()")
2510b1751ae6SLad Prabhakar 	 * [4] = 0	: Power up MIPI HS Tx
2511b1751ae6SLad Prabhakar 	 * [3] = 0	: Power up MIPI LS Rx
2512b1751ae6SLad Prabhakar 	 * [2] = 0	: MIPI interface disabled
2513b1751ae6SLad Prabhakar 	 */
2514b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x40);
2515b1751ae6SLad Prabhakar 	if (ret)
2516b1751ae6SLad Prabhakar 		return ret;
2517b1751ae6SLad Prabhakar 
2518b1751ae6SLad Prabhakar 	/*
2519b1751ae6SLad Prabhakar 	 * Gate clock and set LP11 in 'no packets mode' (idle)
2520b1751ae6SLad Prabhakar 	 *
2521b1751ae6SLad Prabhakar 	 * 0x4800 = 0x24
2522b1751ae6SLad Prabhakar 	 * [5] = 1	: Gate clock when 'no packets'
2523b1751ae6SLad Prabhakar 	 * [2] = 1	: MIPI bus in LP11 when 'no packets'
2524b1751ae6SLad Prabhakar 	 */
2525b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x24);
2526b1751ae6SLad Prabhakar 	if (ret)
2527b1751ae6SLad Prabhakar 		return ret;
2528b1751ae6SLad Prabhakar 
2529b1751ae6SLad Prabhakar 	/*
2530b1751ae6SLad Prabhakar 	 * Set data lanes and clock in LP11 when 'sleeping'
2531b1751ae6SLad Prabhakar 	 *
2532b1751ae6SLad Prabhakar 	 * 0x3019 = 0x70
2533b1751ae6SLad Prabhakar 	 * [6] = 1	: MIPI data lane 2 in LP11 when 'sleeping'
2534b1751ae6SLad Prabhakar 	 * [5] = 1	: MIPI data lane 1 in LP11 when 'sleeping'
2535b1751ae6SLad Prabhakar 	 * [4] = 1	: MIPI clock lane in LP11 when 'sleeping'
2536b1751ae6SLad Prabhakar 	 */
2537b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x70);
2538b1751ae6SLad Prabhakar 	if (ret)
2539b1751ae6SLad Prabhakar 		return ret;
2540b1751ae6SLad Prabhakar 
2541b1751ae6SLad Prabhakar 	/* Give lanes some time to coax into LP11 state. */
2542b1751ae6SLad Prabhakar 	usleep_range(500, 1000);
2543b1751ae6SLad Prabhakar 
2544b1751ae6SLad Prabhakar 	return 0;
2545b1751ae6SLad Prabhakar }
2546b1751ae6SLad Prabhakar 
2547576f5d4bSLad Prabhakar static int ov5640_set_power_dvp(struct ov5640_dev *sensor, bool on)
2548576f5d4bSLad Prabhakar {
2549311a6408SLad Prabhakar 	unsigned int flags = sensor->ep.bus.parallel.flags;
255068579b32SHugues Fruchet 	bool bt656 = sensor->ep.bus_type == V4L2_MBUS_BT656;
255168579b32SHugues Fruchet 	u8 polarities = 0;
2552576f5d4bSLad Prabhakar 	int ret;
2553576f5d4bSLad Prabhakar 
2554576f5d4bSLad Prabhakar 	if (!on) {
2555576f5d4bSLad Prabhakar 		/* Reset settings to their default values. */
255668579b32SHugues Fruchet 		ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00, 0x00);
2557311a6408SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
2558311a6408SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, 0x20);
2559576f5d4bSLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01, 0x00);
2560576f5d4bSLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0x00);
2561576f5d4bSLad Prabhakar 		return 0;
2562576f5d4bSLad Prabhakar 	}
2563576f5d4bSLad Prabhakar 
2564576f5d4bSLad Prabhakar 	/*
2565311a6408SLad Prabhakar 	 * Note about parallel port configuration.
2566311a6408SLad Prabhakar 	 *
2567311a6408SLad Prabhakar 	 * When configured in parallel mode, the OV5640 will
2568311a6408SLad Prabhakar 	 * output 10 bits data on DVP data lines [9:0].
2569311a6408SLad Prabhakar 	 * If only 8 bits data are wanted, the 8 bits data lines
2570311a6408SLad Prabhakar 	 * of the camera interface must be physically connected
2571311a6408SLad Prabhakar 	 * on the DVP data lines [9:2].
2572311a6408SLad Prabhakar 	 *
2573311a6408SLad Prabhakar 	 * Control lines polarity can be configured through
2574311a6408SLad Prabhakar 	 * devicetree endpoint control lines properties.
2575311a6408SLad Prabhakar 	 * If no endpoint control lines properties are set,
2576311a6408SLad Prabhakar 	 * polarity will be as below:
2577311a6408SLad Prabhakar 	 * - VSYNC:	active high
2578311a6408SLad Prabhakar 	 * - HREF:	active low
2579311a6408SLad Prabhakar 	 * - PCLK:	active low
258068579b32SHugues Fruchet 	 *
258168579b32SHugues Fruchet 	 * VSYNC & HREF are not configured if BT656 bus mode is selected
2582311a6408SLad Prabhakar 	 */
258368579b32SHugues Fruchet 
258468579b32SHugues Fruchet 	/*
258568579b32SHugues Fruchet 	 * BT656 embedded synchronization configuration
258668579b32SHugues Fruchet 	 *
258768579b32SHugues Fruchet 	 * CCIR656 CTRL00
258868579b32SHugues Fruchet 	 * - [7]:	SYNC code selection (0: auto generate sync code,
258968579b32SHugues Fruchet 	 *		1: sync code from regs 0x4732-0x4735)
259068579b32SHugues Fruchet 	 * - [6]:	f value in CCIR656 SYNC code when fixed f value
259168579b32SHugues Fruchet 	 * - [5]:	Fixed f value
259268579b32SHugues Fruchet 	 * - [4:3]:	Blank toggle data options (00: data=1'h040/1'h200,
259368579b32SHugues Fruchet 	 *		01: data from regs 0x4736-0x4738, 10: always keep 0)
259468579b32SHugues Fruchet 	 * - [1]:	Clip data disable
259568579b32SHugues Fruchet 	 * - [0]:	CCIR656 mode enable
259668579b32SHugues Fruchet 	 *
259768579b32SHugues Fruchet 	 * Default CCIR656 SAV/EAV mode with default codes
259868579b32SHugues Fruchet 	 * SAV=0xff000080 & EAV=0xff00009d is enabled here with settings:
259968579b32SHugues Fruchet 	 * - CCIR656 mode enable
260068579b32SHugues Fruchet 	 * - auto generation of sync codes
260168579b32SHugues Fruchet 	 * - blank toggle data 1'h040/1'h200
260268579b32SHugues Fruchet 	 * - clip reserved data (0x00 & 0xff changed to 0x01 & 0xfe)
260368579b32SHugues Fruchet 	 */
260468579b32SHugues Fruchet 	ret = ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00,
260568579b32SHugues Fruchet 			       bt656 ? 0x01 : 0x00);
260668579b32SHugues Fruchet 	if (ret)
260768579b32SHugues Fruchet 		return ret;
260868579b32SHugues Fruchet 
2609311a6408SLad Prabhakar 	/*
2610311a6408SLad Prabhakar 	 * configure parallel port control lines polarity
2611311a6408SLad Prabhakar 	 *
2612311a6408SLad Prabhakar 	 * POLARITY CTRL0
2613311a6408SLad Prabhakar 	 * - [5]:	PCLK polarity (0: active low, 1: active high)
2614311a6408SLad Prabhakar 	 * - [1]:	HREF polarity (0: active low, 1: active high)
2615311a6408SLad Prabhakar 	 * - [0]:	VSYNC polarity (mismatch here between
2616311a6408SLad Prabhakar 	 *		datasheet and hardware, 0 is active high
2617311a6408SLad Prabhakar 	 *		and 1 is active low...)
2618311a6408SLad Prabhakar 	 */
261968579b32SHugues Fruchet 	if (!bt656) {
2620311a6408SLad Prabhakar 		if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
262168579b32SHugues Fruchet 			polarities |= BIT(1);
2622311a6408SLad Prabhakar 		if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
262368579b32SHugues Fruchet 			polarities |= BIT(0);
262468579b32SHugues Fruchet 	}
262568579b32SHugues Fruchet 	if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
262668579b32SHugues Fruchet 		polarities |= BIT(5);
2627311a6408SLad Prabhakar 
262868579b32SHugues Fruchet 	ret = ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, polarities);
2629311a6408SLad Prabhakar 	if (ret)
2630311a6408SLad Prabhakar 		return ret;
2631311a6408SLad Prabhakar 
2632311a6408SLad Prabhakar 	/*
263368579b32SHugues Fruchet 	 * powerdown MIPI TX/RX PHY & enable DVP
2634311a6408SLad Prabhakar 	 *
2635311a6408SLad Prabhakar 	 * MIPI CONTROL 00
263668579b32SHugues Fruchet 	 * [4] = 1	: Power down MIPI HS Tx
263768579b32SHugues Fruchet 	 * [3] = 1	: Power down MIPI LS Rx
263868579b32SHugues Fruchet 	 * [2] = 0	: DVP enable (MIPI disable)
2639311a6408SLad Prabhakar 	 */
2640311a6408SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x18);
2641311a6408SLad Prabhakar 	if (ret)
2642311a6408SLad Prabhakar 		return ret;
2643311a6408SLad Prabhakar 
2644311a6408SLad Prabhakar 	/*
2645576f5d4bSLad Prabhakar 	 * enable VSYNC/HREF/PCLK DVP control lines
2646576f5d4bSLad Prabhakar 	 * & D[9:6] DVP data lines
2647576f5d4bSLad Prabhakar 	 *
2648576f5d4bSLad Prabhakar 	 * PAD OUTPUT ENABLE 01
2649576f5d4bSLad Prabhakar 	 * - 6:		VSYNC output enable
2650576f5d4bSLad Prabhakar 	 * - 5:		HREF output enable
2651576f5d4bSLad Prabhakar 	 * - 4:		PCLK output enable
2652576f5d4bSLad Prabhakar 	 * - [3:0]:	D[9:6] output enable
2653576f5d4bSLad Prabhakar 	 */
26544039b037SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01,
265568579b32SHugues Fruchet 			       bt656 ? 0x1f : 0x7f);
2656576f5d4bSLad Prabhakar 	if (ret)
2657576f5d4bSLad Prabhakar 		return ret;
2658576f5d4bSLad Prabhakar 
2659576f5d4bSLad Prabhakar 	/*
2660576f5d4bSLad Prabhakar 	 * enable D[5:0] DVP data lines
2661576f5d4bSLad Prabhakar 	 *
2662576f5d4bSLad Prabhakar 	 * PAD OUTPUT ENABLE 02
2663576f5d4bSLad Prabhakar 	 * - [7:2]:	D[5:0] output enable
2664576f5d4bSLad Prabhakar 	 */
2665576f5d4bSLad Prabhakar 	return ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0xfc);
2666576f5d4bSLad Prabhakar }
2667576f5d4bSLad Prabhakar 
26680f7acb52SHugues Fruchet static int ov5640_set_power(struct ov5640_dev *sensor, bool on)
26690f7acb52SHugues Fruchet {
26700f7acb52SHugues Fruchet 	int ret = 0;
26710f7acb52SHugues Fruchet 
26720f7acb52SHugues Fruchet 	if (on) {
26730f7acb52SHugues Fruchet 		ret = ov5640_set_power_on(sensor);
26740f7acb52SHugues Fruchet 		if (ret)
26750f7acb52SHugues Fruchet 			return ret;
26760f7acb52SHugues Fruchet 
267719a81c14SSteve Longerbeam 		ret = ov5640_restore_mode(sensor);
267819a81c14SSteve Longerbeam 		if (ret)
267919a81c14SSteve Longerbeam 			goto power_off;
2680b1751ae6SLad Prabhakar 	}
268119a81c14SSteve Longerbeam 
2682576f5d4bSLad Prabhakar 	if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY)
2683b1751ae6SLad Prabhakar 		ret = ov5640_set_power_mipi(sensor, on);
2684576f5d4bSLad Prabhakar 	else
2685576f5d4bSLad Prabhakar 		ret = ov5640_set_power_dvp(sensor, on);
2686b1751ae6SLad Prabhakar 	if (ret)
2687b1751ae6SLad Prabhakar 		goto power_off;
2688aa4bb8b8SJacopo Mondi 
2689b1751ae6SLad Prabhakar 	if (!on)
2690aa4bb8b8SJacopo Mondi 		ov5640_set_power_off(sensor);
269119a81c14SSteve Longerbeam 
269219a81c14SSteve Longerbeam 	return 0;
269319a81c14SSteve Longerbeam 
269419a81c14SSteve Longerbeam power_off:
26950f7acb52SHugues Fruchet 	ov5640_set_power_off(sensor);
269619a81c14SSteve Longerbeam 	return ret;
269719a81c14SSteve Longerbeam }
269819a81c14SSteve Longerbeam 
269919a81c14SSteve Longerbeam /* --------------- Subdev Operations --------------- */
270019a81c14SSteve Longerbeam 
270119a81c14SSteve Longerbeam static int ov5640_s_power(struct v4l2_subdev *sd, int on)
270219a81c14SSteve Longerbeam {
270319a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
270419a81c14SSteve Longerbeam 	int ret = 0;
270519a81c14SSteve Longerbeam 
270619a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
270719a81c14SSteve Longerbeam 
270819a81c14SSteve Longerbeam 	/*
270919a81c14SSteve Longerbeam 	 * If the power count is modified from 0 to != 0 or from != 0 to 0,
271019a81c14SSteve Longerbeam 	 * update the power state.
271119a81c14SSteve Longerbeam 	 */
271219a81c14SSteve Longerbeam 	if (sensor->power_count == !on) {
271319a81c14SSteve Longerbeam 		ret = ov5640_set_power(sensor, !!on);
271419a81c14SSteve Longerbeam 		if (ret)
271519a81c14SSteve Longerbeam 			goto out;
271619a81c14SSteve Longerbeam 	}
271719a81c14SSteve Longerbeam 
271819a81c14SSteve Longerbeam 	/* Update the power count. */
271919a81c14SSteve Longerbeam 	sensor->power_count += on ? 1 : -1;
272019a81c14SSteve Longerbeam 	WARN_ON(sensor->power_count < 0);
272119a81c14SSteve Longerbeam out:
272219a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
272319a81c14SSteve Longerbeam 
272419a81c14SSteve Longerbeam 	if (on && !ret && sensor->power_count == 1) {
272519a81c14SSteve Longerbeam 		/* restore controls */
272619a81c14SSteve Longerbeam 		ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
272719a81c14SSteve Longerbeam 	}
272819a81c14SSteve Longerbeam 
272919a81c14SSteve Longerbeam 	return ret;
273019a81c14SSteve Longerbeam }
273119a81c14SSteve Longerbeam 
273219a81c14SSteve Longerbeam static int ov5640_try_frame_interval(struct ov5640_dev *sensor,
273319a81c14SSteve Longerbeam 				     struct v4l2_fract *fi,
273419a81c14SSteve Longerbeam 				     u32 width, u32 height)
273519a81c14SSteve Longerbeam {
273619a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
27376530a5ebSJagan Teki 	enum ov5640_frame_rate rate = OV5640_15_FPS;
2738f6cc192fSMaxime Ripard 	int minfps, maxfps, best_fps, fps;
2739f6cc192fSMaxime Ripard 	int i;
274019a81c14SSteve Longerbeam 
274119a81c14SSteve Longerbeam 	minfps = ov5640_framerates[OV5640_15_FPS];
2742e823fb16SMaxime Ripard 	maxfps = ov5640_framerates[OV5640_60_FPS];
274319a81c14SSteve Longerbeam 
274419a81c14SSteve Longerbeam 	if (fi->numerator == 0) {
274519a81c14SSteve Longerbeam 		fi->denominator = maxfps;
274619a81c14SSteve Longerbeam 		fi->numerator = 1;
2747e823fb16SMaxime Ripard 		rate = OV5640_60_FPS;
2748e823fb16SMaxime Ripard 		goto find_mode;
274919a81c14SSteve Longerbeam 	}
275019a81c14SSteve Longerbeam 
2751f6cc192fSMaxime Ripard 	fps = clamp_val(DIV_ROUND_CLOSEST(fi->denominator, fi->numerator),
2752f6cc192fSMaxime Ripard 			minfps, maxfps);
2753f6cc192fSMaxime Ripard 
2754f6cc192fSMaxime Ripard 	best_fps = minfps;
2755f6cc192fSMaxime Ripard 	for (i = 0; i < ARRAY_SIZE(ov5640_framerates); i++) {
2756f6cc192fSMaxime Ripard 		int curr_fps = ov5640_framerates[i];
2757f6cc192fSMaxime Ripard 
2758f6cc192fSMaxime Ripard 		if (abs(curr_fps - fps) < abs(best_fps - fps)) {
2759f6cc192fSMaxime Ripard 			best_fps = curr_fps;
2760f6cc192fSMaxime Ripard 			rate = i;
2761f6cc192fSMaxime Ripard 		}
2762f6cc192fSMaxime Ripard 	}
276319a81c14SSteve Longerbeam 
276419a81c14SSteve Longerbeam 	fi->numerator = 1;
2765f6cc192fSMaxime Ripard 	fi->denominator = best_fps;
276619a81c14SSteve Longerbeam 
2767e823fb16SMaxime Ripard find_mode:
2768b6ae5022SJacopo Mondi 	mode = ov5640_find_mode(sensor, width, height, false);
27695a3ad937SMaxime Ripard 	return mode ? rate : -EINVAL;
277019a81c14SSteve Longerbeam }
277119a81c14SSteve Longerbeam 
277219a81c14SSteve Longerbeam static int ov5640_get_fmt(struct v4l2_subdev *sd,
27730d346d2aSTomi Valkeinen 			  struct v4l2_subdev_state *sd_state,
277419a81c14SSteve Longerbeam 			  struct v4l2_subdev_format *format)
277519a81c14SSteve Longerbeam {
277619a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
277719a81c14SSteve Longerbeam 	struct v4l2_mbus_framefmt *fmt;
277819a81c14SSteve Longerbeam 
277919a81c14SSteve Longerbeam 	if (format->pad != 0)
278019a81c14SSteve Longerbeam 		return -EINVAL;
278119a81c14SSteve Longerbeam 
278219a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
278319a81c14SSteve Longerbeam 
278419a81c14SSteve Longerbeam 	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
27850d346d2aSTomi Valkeinen 		fmt = v4l2_subdev_get_try_format(&sensor->sd, sd_state,
278619a81c14SSteve Longerbeam 						 format->pad);
278719a81c14SSteve Longerbeam 	else
278819a81c14SSteve Longerbeam 		fmt = &sensor->fmt;
278919a81c14SSteve Longerbeam 
279019a81c14SSteve Longerbeam 	format->format = *fmt;
279119a81c14SSteve Longerbeam 
279219a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
279319a81c14SSteve Longerbeam 
279419a81c14SSteve Longerbeam 	return 0;
279519a81c14SSteve Longerbeam }
279619a81c14SSteve Longerbeam 
279719a81c14SSteve Longerbeam static int ov5640_try_fmt_internal(struct v4l2_subdev *sd,
279819a81c14SSteve Longerbeam 				   struct v4l2_mbus_framefmt *fmt,
279919a81c14SSteve Longerbeam 				   enum ov5640_frame_rate fr,
280019a81c14SSteve Longerbeam 				   const struct ov5640_mode_info **new_mode)
280119a81c14SSteve Longerbeam {
280219a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
280319a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
2804a89f14bbSJacopo Mondi 	const struct ov5640_pixfmt *pixfmt;
2805a89f14bbSJacopo Mondi 	unsigned int bpp;
280619a81c14SSteve Longerbeam 
2807b6ae5022SJacopo Mondi 	mode = ov5640_find_mode(sensor, fmt->width, fmt->height, true);
280819a81c14SSteve Longerbeam 	if (!mode)
280919a81c14SSteve Longerbeam 		return -EINVAL;
2810dd81b8ffSJacopo Mondi 
2811a89f14bbSJacopo Mondi 	pixfmt = ov5640_code_to_pixfmt(sensor, fmt->code);
2812a89f14bbSJacopo Mondi 	bpp = pixfmt->bpp;
2813a89f14bbSJacopo Mondi 
2814dd81b8ffSJacopo Mondi 	/*
2815dd81b8ffSJacopo Mondi 	 * Adjust mode according to bpp:
2816dd81b8ffSJacopo Mondi 	 * - 8bpp modes work for resolution >= 1280x720
2817dd81b8ffSJacopo Mondi 	 * - 24bpp modes work resolution < 1280x720
2818dd81b8ffSJacopo Mondi 	 */
2819dd81b8ffSJacopo Mondi 	if (bpp == 8 && mode->width < 1280)
2820dd81b8ffSJacopo Mondi 		mode = &ov5640_mode_data[OV5640_MODE_720P_1280_720];
2821dd81b8ffSJacopo Mondi 	else if (bpp == 24 && mode->width > 1024)
2822dd81b8ffSJacopo Mondi 		mode = &ov5640_mode_data[OV5640_MODE_XGA_1024_768];
2823dd81b8ffSJacopo Mondi 
28245113d5b3SJacopo Mondi 	fmt->width = mode->width;
28255113d5b3SJacopo Mondi 	fmt->height = mode->height;
282619a81c14SSteve Longerbeam 
282719a81c14SSteve Longerbeam 	if (new_mode)
282819a81c14SSteve Longerbeam 		*new_mode = mode;
2829e3ee691dSHugues Fruchet 
2830a89f14bbSJacopo Mondi 	fmt->code = pixfmt->code;
2831a89f14bbSJacopo Mondi 	fmt->colorspace = pixfmt->colorspace;
2832e6441fdeSHugues Fruchet 	fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
2833e6441fdeSHugues Fruchet 	fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
2834e6441fdeSHugues Fruchet 	fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
2835e3ee691dSHugues Fruchet 
283619a81c14SSteve Longerbeam 	return 0;
283719a81c14SSteve Longerbeam }
283819a81c14SSteve Longerbeam 
28393c28588fSJacopo Mondi static int ov5640_update_pixel_rate(struct ov5640_dev *sensor)
28403c28588fSJacopo Mondi {
28413c28588fSJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
28423c28588fSJacopo Mondi 	enum ov5640_pixel_rate_id pixel_rate_id = mode->pixel_rate;
28433c28588fSJacopo Mondi 	struct v4l2_mbus_framefmt *fmt = &sensor->fmt;
284432979f67SJacopo Mondi 	const struct ov5640_timings *timings;
2845bce93b82SJacopo Mondi 	s32 exposure_val, exposure_max;
284632979f67SJacopo Mondi 	unsigned int hblank;
28473c28588fSJacopo Mondi 	unsigned int i = 0;
28483c28588fSJacopo Mondi 	u32 pixel_rate;
28493c28588fSJacopo Mondi 	s64 link_freq;
28503c28588fSJacopo Mondi 	u32 num_lanes;
285119f2e3e6SHugues Fruchet 	u32 vblank;
28523c28588fSJacopo Mondi 	u32 bpp;
28533c28588fSJacopo Mondi 
28543c28588fSJacopo Mondi 	/*
28553c28588fSJacopo Mondi 	 * Update the pixel rate control value.
28563c28588fSJacopo Mondi 	 *
28573c28588fSJacopo Mondi 	 * For DVP mode, maintain the pixel rate calculation using fixed FPS.
28583c28588fSJacopo Mondi 	 */
28593c28588fSJacopo Mondi 	if (!ov5640_is_csi2(sensor)) {
28603c28588fSJacopo Mondi 		__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate,
28613c28588fSJacopo Mondi 					 ov5640_calc_pixel_rate(sensor));
28623c28588fSJacopo Mondi 
28633c28588fSJacopo Mondi 		return 0;
28643c28588fSJacopo Mondi 	}
28653c28588fSJacopo Mondi 
28663c28588fSJacopo Mondi 	/*
28673c28588fSJacopo Mondi 	 * The MIPI CSI-2 link frequency should comply with the CSI-2
28683c28588fSJacopo Mondi 	 * specification and be lower than 1GHz.
28693c28588fSJacopo Mondi 	 *
28703c28588fSJacopo Mondi 	 * Start from the suggested pixel_rate for the current mode and
28713c28588fSJacopo Mondi 	 * progressively slow it down if it exceeds 1GHz.
28723c28588fSJacopo Mondi 	 */
28733c28588fSJacopo Mondi 	num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes;
2874a89f14bbSJacopo Mondi 	bpp = ov5640_code_to_bpp(sensor, fmt->code);
28753c28588fSJacopo Mondi 	do {
28763c28588fSJacopo Mondi 		pixel_rate = ov5640_pixel_rates[pixel_rate_id];
28773c28588fSJacopo Mondi 		link_freq = pixel_rate * bpp / (2 * num_lanes);
28783c28588fSJacopo Mondi 	} while (link_freq >= 1000000000U &&
28793c28588fSJacopo Mondi 		 ++pixel_rate_id < OV5640_NUM_PIXEL_RATES);
28803c28588fSJacopo Mondi 
28813c28588fSJacopo Mondi 	sensor->current_link_freq = link_freq;
28823c28588fSJacopo Mondi 
28833c28588fSJacopo Mondi 	/*
28843c28588fSJacopo Mondi 	 * Higher link rates require the clock tree to be programmed with
28853c28588fSJacopo Mondi 	 * 'mipi_div' = 1; this has the effect of halving the actual output
28863c28588fSJacopo Mondi 	 * pixel rate in the MIPI domain.
28873c28588fSJacopo Mondi 	 *
28883c28588fSJacopo Mondi 	 * Adjust the pixel rate and link frequency control value to report it
28893c28588fSJacopo Mondi 	 * correctly to userspace.
28903c28588fSJacopo Mondi 	 */
28913c28588fSJacopo Mondi 	if (link_freq > OV5640_LINK_RATE_MAX) {
28923c28588fSJacopo Mondi 		pixel_rate /= 2;
28933c28588fSJacopo Mondi 		link_freq /= 2;
28943c28588fSJacopo Mondi 	}
28953c28588fSJacopo Mondi 
28963c28588fSJacopo Mondi 	for (i = 0; i < ARRAY_SIZE(ov5640_csi2_link_freqs); ++i) {
28973c28588fSJacopo Mondi 		if (ov5640_csi2_link_freqs[i] == link_freq)
28983c28588fSJacopo Mondi 			break;
28993c28588fSJacopo Mondi 	}
29003c28588fSJacopo Mondi 	WARN_ON(i == ARRAY_SIZE(ov5640_csi2_link_freqs));
29013c28588fSJacopo Mondi 
29023c28588fSJacopo Mondi 	__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, pixel_rate);
29033c28588fSJacopo Mondi 	__v4l2_ctrl_s_ctrl(sensor->ctrls.link_freq, i);
29043c28588fSJacopo Mondi 
290532979f67SJacopo Mondi 	timings = ov5640_timings(sensor, mode);
290632979f67SJacopo Mondi 	hblank = timings->htot - mode->width;
290732979f67SJacopo Mondi 	__v4l2_ctrl_modify_range(sensor->ctrls.hblank,
290832979f67SJacopo Mondi 				 hblank, hblank, 1, hblank);
290932979f67SJacopo Mondi 
291019f2e3e6SHugues Fruchet 	vblank = timings->vblank_def;
2911bce93b82SJacopo Mondi 
291219f2e3e6SHugues Fruchet 	if (sensor->current_fr != mode->def_fps) {
291319f2e3e6SHugues Fruchet 		/*
291419f2e3e6SHugues Fruchet 		 * Compute the vertical blanking according to the framerate
291519f2e3e6SHugues Fruchet 		 * configured with s_frame_interval.
291619f2e3e6SHugues Fruchet 		 */
291719f2e3e6SHugues Fruchet 		int fie_num = sensor->frame_interval.numerator;
291819f2e3e6SHugues Fruchet 		int fie_denom = sensor->frame_interval.denominator;
291919f2e3e6SHugues Fruchet 
292019f2e3e6SHugues Fruchet 		vblank = ((fie_num * pixel_rate / fie_denom) / timings->htot) -
292119f2e3e6SHugues Fruchet 			mode->height;
292219f2e3e6SHugues Fruchet 	}
292319f2e3e6SHugues Fruchet 
292419f2e3e6SHugues Fruchet 	__v4l2_ctrl_modify_range(sensor->ctrls.vblank, OV5640_MIN_VBLANK,
292519f2e3e6SHugues Fruchet 				 OV5640_MAX_VTS - mode->height, 1, vblank);
292619f2e3e6SHugues Fruchet 	__v4l2_ctrl_s_ctrl(sensor->ctrls.vblank, vblank);
292719f2e3e6SHugues Fruchet 
292819f2e3e6SHugues Fruchet 	exposure_max = timings->crop.height + vblank - 4;
2929bce93b82SJacopo Mondi 	exposure_val = clamp_t(s32, sensor->ctrls.exposure->val,
2930bce93b82SJacopo Mondi 			       sensor->ctrls.exposure->minimum,
2931bce93b82SJacopo Mondi 			       exposure_max);
293219f2e3e6SHugues Fruchet 
2933bce93b82SJacopo Mondi 	__v4l2_ctrl_modify_range(sensor->ctrls.exposure,
2934bce93b82SJacopo Mondi 				 sensor->ctrls.exposure->minimum,
2935bce93b82SJacopo Mondi 				 exposure_max, 1, exposure_val);
2936bce93b82SJacopo Mondi 
29373c28588fSJacopo Mondi 	return 0;
29383c28588fSJacopo Mondi }
29393c28588fSJacopo Mondi 
294019a81c14SSteve Longerbeam static int ov5640_set_fmt(struct v4l2_subdev *sd,
29410d346d2aSTomi Valkeinen 			  struct v4l2_subdev_state *sd_state,
294219a81c14SSteve Longerbeam 			  struct v4l2_subdev_format *format)
294319a81c14SSteve Longerbeam {
294419a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
294519a81c14SSteve Longerbeam 	const struct ov5640_mode_info *new_mode;
2946e6441fdeSHugues Fruchet 	struct v4l2_mbus_framefmt *mbus_fmt = &format->format;
294719a81c14SSteve Longerbeam 	int ret;
294819a81c14SSteve Longerbeam 
294919a81c14SSteve Longerbeam 	if (format->pad != 0)
295019a81c14SSteve Longerbeam 		return -EINVAL;
295119a81c14SSteve Longerbeam 
295219a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
295319a81c14SSteve Longerbeam 
295419a81c14SSteve Longerbeam 	if (sensor->streaming) {
295519a81c14SSteve Longerbeam 		ret = -EBUSY;
295619a81c14SSteve Longerbeam 		goto out;
295719a81c14SSteve Longerbeam 	}
295819a81c14SSteve Longerbeam 
2959e6441fdeSHugues Fruchet 	ret = ov5640_try_fmt_internal(sd, mbus_fmt,
296019a81c14SSteve Longerbeam 				      sensor->current_fr, &new_mode);
296119a81c14SSteve Longerbeam 	if (ret)
296219a81c14SSteve Longerbeam 		goto out;
296319a81c14SSteve Longerbeam 
2964e738f5ddSMirela Rabulea 	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
2965e738f5ddSMirela Rabulea 		*v4l2_subdev_get_try_format(sd, sd_state, 0) = *mbus_fmt;
2966e738f5ddSMirela Rabulea 		goto out;
2967e738f5ddSMirela Rabulea 	}
296819a81c14SSteve Longerbeam 
29696949d864SHugues Fruchet 	if (new_mode != sensor->current_mode) {
297019f2e3e6SHugues Fruchet 		sensor->current_fr = new_mode->def_fps;
297119a81c14SSteve Longerbeam 		sensor->current_mode = new_mode;
297219a81c14SSteve Longerbeam 		sensor->pending_mode_change = true;
29736949d864SHugues Fruchet 	}
297407115449SJacopo Mondi 	if (mbus_fmt->code != sensor->fmt.code)
2975fb98e29fSHugues Fruchet 		sensor->pending_fmt_change = true;
297607115449SJacopo Mondi 
2977e738f5ddSMirela Rabulea 	/* update format even if code is unchanged, resolution might change */
2978e738f5ddSMirela Rabulea 	sensor->fmt = *mbus_fmt;
2979e738f5ddSMirela Rabulea 
29803c28588fSJacopo Mondi 	ov5640_update_pixel_rate(sensor);
29813c28588fSJacopo Mondi 
298219a81c14SSteve Longerbeam out:
298319a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
298419a81c14SSteve Longerbeam 	return ret;
298519a81c14SSteve Longerbeam }
298619a81c14SSteve Longerbeam 
298766ed85ebSJacopo Mondi static int ov5640_get_selection(struct v4l2_subdev *sd,
298866ed85ebSJacopo Mondi 				struct v4l2_subdev_state *sd_state,
298966ed85ebSJacopo Mondi 				struct v4l2_subdev_selection *sel)
299066ed85ebSJacopo Mondi {
299166ed85ebSJacopo Mondi 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
299266ed85ebSJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
299366ed85ebSJacopo Mondi 	const struct ov5640_timings *timings;
299466ed85ebSJacopo Mondi 
299566ed85ebSJacopo Mondi 	switch (sel->target) {
299666ed85ebSJacopo Mondi 	case V4L2_SEL_TGT_CROP: {
299766ed85ebSJacopo Mondi 		mutex_lock(&sensor->lock);
299866ed85ebSJacopo Mondi 		timings = ov5640_timings(sensor, mode);
299966ed85ebSJacopo Mondi 		sel->r = timings->analog_crop;
300066ed85ebSJacopo Mondi 		mutex_unlock(&sensor->lock);
300166ed85ebSJacopo Mondi 
300266ed85ebSJacopo Mondi 		return 0;
300366ed85ebSJacopo Mondi 	}
300466ed85ebSJacopo Mondi 
300566ed85ebSJacopo Mondi 	case V4L2_SEL_TGT_NATIVE_SIZE:
300666ed85ebSJacopo Mondi 	case V4L2_SEL_TGT_CROP_BOUNDS:
300766ed85ebSJacopo Mondi 		sel->r.top = 0;
300866ed85ebSJacopo Mondi 		sel->r.left = 0;
300966ed85ebSJacopo Mondi 		sel->r.width = OV5640_NATIVE_WIDTH;
301066ed85ebSJacopo Mondi 		sel->r.height = OV5640_NATIVE_HEIGHT;
301166ed85ebSJacopo Mondi 
301266ed85ebSJacopo Mondi 		return 0;
301366ed85ebSJacopo Mondi 
301466ed85ebSJacopo Mondi 	case V4L2_SEL_TGT_CROP_DEFAULT:
301566ed85ebSJacopo Mondi 		sel->r.top = OV5640_PIXEL_ARRAY_TOP;
301666ed85ebSJacopo Mondi 		sel->r.left = OV5640_PIXEL_ARRAY_LEFT;
301766ed85ebSJacopo Mondi 		sel->r.width = OV5640_PIXEL_ARRAY_WIDTH;
301866ed85ebSJacopo Mondi 		sel->r.height = OV5640_PIXEL_ARRAY_HEIGHT;
301966ed85ebSJacopo Mondi 
302066ed85ebSJacopo Mondi 		return 0;
302166ed85ebSJacopo Mondi 	}
302266ed85ebSJacopo Mondi 
302366ed85ebSJacopo Mondi 	return -EINVAL;
302466ed85ebSJacopo Mondi }
302566ed85ebSJacopo Mondi 
3026e3ee691dSHugues Fruchet static int ov5640_set_framefmt(struct ov5640_dev *sensor,
3027e3ee691dSHugues Fruchet 			       struct v4l2_mbus_framefmt *format)
3028e3ee691dSHugues Fruchet {
3029935fbc94SJacopo Mondi 	bool is_jpeg = format->code == MEDIA_BUS_FMT_JPEG_1X8;
3030935fbc94SJacopo Mondi 	const struct ov5640_pixfmt *pixfmt;
3031e3ee691dSHugues Fruchet 	int ret = 0;
3032e3ee691dSHugues Fruchet 
3033935fbc94SJacopo Mondi 	pixfmt = ov5640_code_to_pixfmt(sensor, format->code);
3034e3ee691dSHugues Fruchet 
3035e3ee691dSHugues Fruchet 	/* FORMAT CONTROL00: YUV and RGB formatting */
3036935fbc94SJacopo Mondi 	ret = ov5640_write_reg(sensor, OV5640_REG_FORMAT_CONTROL00,
3037935fbc94SJacopo Mondi 			       pixfmt->ctrl00);
3038e3ee691dSHugues Fruchet 	if (ret)
3039e3ee691dSHugues Fruchet 		return ret;
3040e3ee691dSHugues Fruchet 
3041e3ee691dSHugues Fruchet 	/* FORMAT MUX CONTROL: ISP YUV or RGB */
3042935fbc94SJacopo Mondi 	ret = ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL,
3043935fbc94SJacopo Mondi 			       pixfmt->mux);
3044d47c4126SHugues Fruchet 	if (ret)
3045d47c4126SHugues Fruchet 		return ret;
3046d47c4126SHugues Fruchet 
3047d47c4126SHugues Fruchet 	/*
3048d47c4126SHugues Fruchet 	 * TIMING TC REG21:
3049d47c4126SHugues Fruchet 	 * - [5]:	JPEG enable
3050d47c4126SHugues Fruchet 	 */
3051d47c4126SHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
3052d47c4126SHugues Fruchet 			     BIT(5), is_jpeg ? BIT(5) : 0);
3053d47c4126SHugues Fruchet 	if (ret)
3054d47c4126SHugues Fruchet 		return ret;
3055d47c4126SHugues Fruchet 
3056d47c4126SHugues Fruchet 	/*
3057d47c4126SHugues Fruchet 	 * SYSTEM RESET02:
3058d47c4126SHugues Fruchet 	 * - [4]:	Reset JFIFO
3059d47c4126SHugues Fruchet 	 * - [3]:	Reset SFIFO
3060d47c4126SHugues Fruchet 	 * - [2]:	Reset JPEG
3061d47c4126SHugues Fruchet 	 */
3062d47c4126SHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_RESET02,
3063d47c4126SHugues Fruchet 			     BIT(4) | BIT(3) | BIT(2),
3064d47c4126SHugues Fruchet 			     is_jpeg ? 0 : (BIT(4) | BIT(3) | BIT(2)));
3065d47c4126SHugues Fruchet 	if (ret)
3066d47c4126SHugues Fruchet 		return ret;
3067d47c4126SHugues Fruchet 
3068d47c4126SHugues Fruchet 	/*
3069d47c4126SHugues Fruchet 	 * CLOCK ENABLE02:
3070d47c4126SHugues Fruchet 	 * - [5]:	Enable JPEG 2x clock
3071d47c4126SHugues Fruchet 	 * - [3]:	Enable JPEG clock
3072d47c4126SHugues Fruchet 	 */
3073d47c4126SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_SYS_CLOCK_ENABLE02,
3074d47c4126SHugues Fruchet 			      BIT(5) | BIT(3),
3075d47c4126SHugues Fruchet 			      is_jpeg ? (BIT(5) | BIT(3)) : 0);
3076e3ee691dSHugues Fruchet }
307719a81c14SSteve Longerbeam 
307819a81c14SSteve Longerbeam /*
307919a81c14SSteve Longerbeam  * Sensor Controls.
308019a81c14SSteve Longerbeam  */
308119a81c14SSteve Longerbeam 
308219a81c14SSteve Longerbeam static int ov5640_set_ctrl_hue(struct ov5640_dev *sensor, int value)
308319a81c14SSteve Longerbeam {
308419a81c14SSteve Longerbeam 	int ret;
308519a81c14SSteve Longerbeam 
308619a81c14SSteve Longerbeam 	if (value) {
308719a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
308819a81c14SSteve Longerbeam 				     BIT(0), BIT(0));
308919a81c14SSteve Longerbeam 		if (ret)
309019a81c14SSteve Longerbeam 			return ret;
309119a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_SDE_CTRL1, value);
309219a81c14SSteve Longerbeam 	} else {
309319a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(0), 0);
309419a81c14SSteve Longerbeam 	}
309519a81c14SSteve Longerbeam 
309619a81c14SSteve Longerbeam 	return ret;
309719a81c14SSteve Longerbeam }
309819a81c14SSteve Longerbeam 
309919a81c14SSteve Longerbeam static int ov5640_set_ctrl_contrast(struct ov5640_dev *sensor, int value)
310019a81c14SSteve Longerbeam {
310119a81c14SSteve Longerbeam 	int ret;
310219a81c14SSteve Longerbeam 
310319a81c14SSteve Longerbeam 	if (value) {
310419a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
310519a81c14SSteve Longerbeam 				     BIT(2), BIT(2));
310619a81c14SSteve Longerbeam 		if (ret)
310719a81c14SSteve Longerbeam 			return ret;
310819a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL5,
310919a81c14SSteve Longerbeam 				       value & 0xff);
311019a81c14SSteve Longerbeam 	} else {
311119a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(2), 0);
311219a81c14SSteve Longerbeam 	}
311319a81c14SSteve Longerbeam 
311419a81c14SSteve Longerbeam 	return ret;
311519a81c14SSteve Longerbeam }
311619a81c14SSteve Longerbeam 
311719a81c14SSteve Longerbeam static int ov5640_set_ctrl_saturation(struct ov5640_dev *sensor, int value)
311819a81c14SSteve Longerbeam {
311919a81c14SSteve Longerbeam 	int ret;
312019a81c14SSteve Longerbeam 
312119a81c14SSteve Longerbeam 	if (value) {
312219a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
312319a81c14SSteve Longerbeam 				     BIT(1), BIT(1));
312419a81c14SSteve Longerbeam 		if (ret)
312519a81c14SSteve Longerbeam 			return ret;
312619a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL3,
312719a81c14SSteve Longerbeam 				       value & 0xff);
312819a81c14SSteve Longerbeam 		if (ret)
312919a81c14SSteve Longerbeam 			return ret;
313019a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL4,
313119a81c14SSteve Longerbeam 				       value & 0xff);
313219a81c14SSteve Longerbeam 	} else {
313319a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(1), 0);
313419a81c14SSteve Longerbeam 	}
313519a81c14SSteve Longerbeam 
313619a81c14SSteve Longerbeam 	return ret;
313719a81c14SSteve Longerbeam }
313819a81c14SSteve Longerbeam 
313919a81c14SSteve Longerbeam static int ov5640_set_ctrl_white_balance(struct ov5640_dev *sensor, int awb)
314019a81c14SSteve Longerbeam {
314119a81c14SSteve Longerbeam 	int ret;
314219a81c14SSteve Longerbeam 
314319a81c14SSteve Longerbeam 	ret = ov5640_mod_reg(sensor, OV5640_REG_AWB_MANUAL_CTRL,
314419a81c14SSteve Longerbeam 			     BIT(0), awb ? 0 : 1);
314519a81c14SSteve Longerbeam 	if (ret)
314619a81c14SSteve Longerbeam 		return ret;
314719a81c14SSteve Longerbeam 
314819a81c14SSteve Longerbeam 	if (!awb) {
314919a81c14SSteve Longerbeam 		u16 red = (u16)sensor->ctrls.red_balance->val;
315019a81c14SSteve Longerbeam 		u16 blue = (u16)sensor->ctrls.blue_balance->val;
315119a81c14SSteve Longerbeam 
315219a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_R_GAIN, red);
315319a81c14SSteve Longerbeam 		if (ret)
315419a81c14SSteve Longerbeam 			return ret;
315519a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_B_GAIN, blue);
315619a81c14SSteve Longerbeam 	}
315719a81c14SSteve Longerbeam 
315819a81c14SSteve Longerbeam 	return ret;
315919a81c14SSteve Longerbeam }
316019a81c14SSteve Longerbeam 
31613cca8ef5SHugues Fruchet static int ov5640_set_ctrl_exposure(struct ov5640_dev *sensor,
31623cca8ef5SHugues Fruchet 				    enum v4l2_exposure_auto_type auto_exposure)
316319a81c14SSteve Longerbeam {
316419a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
31653cca8ef5SHugues Fruchet 	bool auto_exp = (auto_exposure == V4L2_EXPOSURE_AUTO);
316619a81c14SSteve Longerbeam 	int ret = 0;
316719a81c14SSteve Longerbeam 
316819a81c14SSteve Longerbeam 	if (ctrls->auto_exp->is_new) {
31693cca8ef5SHugues Fruchet 		ret = ov5640_set_autoexposure(sensor, auto_exp);
317019a81c14SSteve Longerbeam 		if (ret)
317119a81c14SSteve Longerbeam 			return ret;
317219a81c14SSteve Longerbeam 	}
317319a81c14SSteve Longerbeam 
31743cca8ef5SHugues Fruchet 	if (!auto_exp && ctrls->exposure->is_new) {
317519a81c14SSteve Longerbeam 		u16 max_exp;
317619a81c14SSteve Longerbeam 
317719a81c14SSteve Longerbeam 		ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_VTS,
317819a81c14SSteve Longerbeam 					&max_exp);
317919a81c14SSteve Longerbeam 		if (ret)
318019a81c14SSteve Longerbeam 			return ret;
318119a81c14SSteve Longerbeam 		ret = ov5640_get_vts(sensor);
318219a81c14SSteve Longerbeam 		if (ret < 0)
318319a81c14SSteve Longerbeam 			return ret;
318419a81c14SSteve Longerbeam 		max_exp += ret;
31856146fde3SHugues Fruchet 		ret = 0;
318619a81c14SSteve Longerbeam 
318719a81c14SSteve Longerbeam 		if (ctrls->exposure->val < max_exp)
318819a81c14SSteve Longerbeam 			ret = ov5640_set_exposure(sensor, ctrls->exposure->val);
318919a81c14SSteve Longerbeam 	}
319019a81c14SSteve Longerbeam 
319119a81c14SSteve Longerbeam 	return ret;
319219a81c14SSteve Longerbeam }
319319a81c14SSteve Longerbeam 
31943cca8ef5SHugues Fruchet static int ov5640_set_ctrl_gain(struct ov5640_dev *sensor, bool auto_gain)
319519a81c14SSteve Longerbeam {
319619a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
319719a81c14SSteve Longerbeam 	int ret = 0;
319819a81c14SSteve Longerbeam 
319919a81c14SSteve Longerbeam 	if (ctrls->auto_gain->is_new) {
32003cca8ef5SHugues Fruchet 		ret = ov5640_set_autogain(sensor, auto_gain);
320119a81c14SSteve Longerbeam 		if (ret)
320219a81c14SSteve Longerbeam 			return ret;
320319a81c14SSteve Longerbeam 	}
320419a81c14SSteve Longerbeam 
32053cca8ef5SHugues Fruchet 	if (!auto_gain && ctrls->gain->is_new)
32063cca8ef5SHugues Fruchet 		ret = ov5640_set_gain(sensor, ctrls->gain->val);
320719a81c14SSteve Longerbeam 
320819a81c14SSteve Longerbeam 	return ret;
320919a81c14SSteve Longerbeam }
321019a81c14SSteve Longerbeam 
32119f6d7bacSChen-Yu Tsai static const char * const test_pattern_menu[] = {
32129f6d7bacSChen-Yu Tsai 	"Disabled",
32139f6d7bacSChen-Yu Tsai 	"Color bars",
3214bddc5cdfSChen-Yu Tsai 	"Color bars w/ rolling bar",
3215bddc5cdfSChen-Yu Tsai 	"Color squares",
3216bddc5cdfSChen-Yu Tsai 	"Color squares w/ rolling bar",
32179f6d7bacSChen-Yu Tsai };
32189f6d7bacSChen-Yu Tsai 
3219a0c29afbSChen-Yu Tsai #define OV5640_TEST_ENABLE		BIT(7)
3220a0c29afbSChen-Yu Tsai #define OV5640_TEST_ROLLING		BIT(6)	/* rolling horizontal bar */
3221a0c29afbSChen-Yu Tsai #define OV5640_TEST_TRANSPARENT		BIT(5)
3222a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE_BW		BIT(4)	/* black & white squares */
3223a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_STANDARD	(0 << 2)
3224a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_1	(1 << 2)
3225a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_HOR_CHANGE	(2 << 2)
3226a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_2	(3 << 2)
3227a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR			(0 << 0)
3228a0c29afbSChen-Yu Tsai #define OV5640_TEST_RANDOM		(1 << 0)
3229a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE		(2 << 0)
3230a0c29afbSChen-Yu Tsai #define OV5640_TEST_BLACK		(3 << 0)
3231a0c29afbSChen-Yu Tsai 
3232a0c29afbSChen-Yu Tsai static const u8 test_pattern_val[] = {
3233a0c29afbSChen-Yu Tsai 	0,
32342aff1fc3SChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_BAR_VERT_CHANGE_1 |
3235a0c29afbSChen-Yu Tsai 		OV5640_TEST_BAR,
3236bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_ROLLING |
3237bddc5cdfSChen-Yu Tsai 		OV5640_TEST_BAR_VERT_CHANGE_1 | OV5640_TEST_BAR,
3238bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_SQUARE,
3239bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_ROLLING | OV5640_TEST_SQUARE,
3240a0c29afbSChen-Yu Tsai };
3241a0c29afbSChen-Yu Tsai 
324219a81c14SSteve Longerbeam static int ov5640_set_ctrl_test_pattern(struct ov5640_dev *sensor, int value)
324319a81c14SSteve Longerbeam {
3244a0c29afbSChen-Yu Tsai 	return ov5640_write_reg(sensor, OV5640_REG_PRE_ISP_TEST_SET1,
3245a0c29afbSChen-Yu Tsai 				test_pattern_val[value]);
324619a81c14SSteve Longerbeam }
324719a81c14SSteve Longerbeam 
32481068fecaSMylène Josserand static int ov5640_set_ctrl_light_freq(struct ov5640_dev *sensor, int value)
32491068fecaSMylène Josserand {
32501068fecaSMylène Josserand 	int ret;
32511068fecaSMylène Josserand 
32521068fecaSMylène Josserand 	ret = ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL01, BIT(7),
32531068fecaSMylène Josserand 			     (value == V4L2_CID_POWER_LINE_FREQUENCY_AUTO) ?
32541068fecaSMylène Josserand 			     0 : BIT(7));
32551068fecaSMylène Josserand 	if (ret)
32561068fecaSMylène Josserand 		return ret;
32571068fecaSMylène Josserand 
32581068fecaSMylène Josserand 	return ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL00, BIT(2),
32591068fecaSMylène Josserand 			      (value == V4L2_CID_POWER_LINE_FREQUENCY_50HZ) ?
32601068fecaSMylène Josserand 			      BIT(2) : 0);
32611068fecaSMylène Josserand }
32621068fecaSMylène Josserand 
3263ce85705aSHugues Fruchet static int ov5640_set_ctrl_hflip(struct ov5640_dev *sensor, int value)
3264ce85705aSHugues Fruchet {
3265ce85705aSHugues Fruchet 	/*
3266c3f3ba3eSHugues Fruchet 	 * If sensor is mounted upside down, mirror logic is inversed.
3267c3f3ba3eSHugues Fruchet 	 *
3268ce85705aSHugues Fruchet 	 * Sensor is a BSI (Back Side Illuminated) one,
3269ce85705aSHugues Fruchet 	 * so image captured is physically mirrored.
3270ce85705aSHugues Fruchet 	 * This is why mirror logic is inversed in
3271ce85705aSHugues Fruchet 	 * order to cancel this mirror effect.
3272ce85705aSHugues Fruchet 	 */
3273ce85705aSHugues Fruchet 
3274ce85705aSHugues Fruchet 	/*
3275ce85705aSHugues Fruchet 	 * TIMING TC REG21:
3276ce85705aSHugues Fruchet 	 * - [2]:	ISP mirror
3277ce85705aSHugues Fruchet 	 * - [1]:	Sensor mirror
3278ce85705aSHugues Fruchet 	 */
3279ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
3280ce85705aSHugues Fruchet 			      BIT(2) | BIT(1),
3281c3f3ba3eSHugues Fruchet 			      (!(value ^ sensor->upside_down)) ?
3282c3f3ba3eSHugues Fruchet 			      (BIT(2) | BIT(1)) : 0);
3283ce85705aSHugues Fruchet }
3284ce85705aSHugues Fruchet 
3285ce85705aSHugues Fruchet static int ov5640_set_ctrl_vflip(struct ov5640_dev *sensor, int value)
3286ce85705aSHugues Fruchet {
3287c3f3ba3eSHugues Fruchet 	/* If sensor is mounted upside down, flip logic is inversed */
3288c3f3ba3eSHugues Fruchet 
3289ce85705aSHugues Fruchet 	/*
3290ce85705aSHugues Fruchet 	 * TIMING TC REG20:
3291ce85705aSHugues Fruchet 	 * - [2]:	ISP vflip
3292ce85705aSHugues Fruchet 	 * - [1]:	Sensor vflip
3293ce85705aSHugues Fruchet 	 */
3294ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20,
3295ce85705aSHugues Fruchet 			      BIT(2) | BIT(1),
3296c3f3ba3eSHugues Fruchet 			      (value ^ sensor->upside_down) ?
3297c3f3ba3eSHugues Fruchet 			      (BIT(2) | BIT(1)) : 0);
3298ce85705aSHugues Fruchet }
3299ce85705aSHugues Fruchet 
3300bce93b82SJacopo Mondi static int ov5640_set_ctrl_vblank(struct ov5640_dev *sensor, int value)
3301bce93b82SJacopo Mondi {
3302bce93b82SJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
3303bce93b82SJacopo Mondi 
3304bce93b82SJacopo Mondi 	/* Update the VTOT timing register value. */
3305bce93b82SJacopo Mondi 	return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS,
3306bce93b82SJacopo Mondi 				  mode->height + value);
3307bce93b82SJacopo Mondi }
3308bce93b82SJacopo Mondi 
330919a81c14SSteve Longerbeam static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
331019a81c14SSteve Longerbeam {
331119a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
331219a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
331319a81c14SSteve Longerbeam 	int val;
331419a81c14SSteve Longerbeam 
331519a81c14SSteve Longerbeam 	/* v4l2_ctrl_lock() locks our own mutex */
331619a81c14SSteve Longerbeam 
331719a81c14SSteve Longerbeam 	switch (ctrl->id) {
331819a81c14SSteve Longerbeam 	case V4L2_CID_AUTOGAIN:
331919a81c14SSteve Longerbeam 		val = ov5640_get_gain(sensor);
332019a81c14SSteve Longerbeam 		if (val < 0)
332119a81c14SSteve Longerbeam 			return val;
332219a81c14SSteve Longerbeam 		sensor->ctrls.gain->val = val;
332319a81c14SSteve Longerbeam 		break;
332419a81c14SSteve Longerbeam 	case V4L2_CID_EXPOSURE_AUTO:
332519a81c14SSteve Longerbeam 		val = ov5640_get_exposure(sensor);
332619a81c14SSteve Longerbeam 		if (val < 0)
332719a81c14SSteve Longerbeam 			return val;
332819a81c14SSteve Longerbeam 		sensor->ctrls.exposure->val = val;
332919a81c14SSteve Longerbeam 		break;
333019a81c14SSteve Longerbeam 	}
333119a81c14SSteve Longerbeam 
333219a81c14SSteve Longerbeam 	return 0;
333319a81c14SSteve Longerbeam }
333419a81c14SSteve Longerbeam 
333519a81c14SSteve Longerbeam static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl)
333619a81c14SSteve Longerbeam {
333719a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
333819a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
3339bce93b82SJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
3340bce93b82SJacopo Mondi 	const struct ov5640_timings *timings;
3341bce93b82SJacopo Mondi 	unsigned int exp_max;
334219a81c14SSteve Longerbeam 	int ret;
334319a81c14SSteve Longerbeam 
334419a81c14SSteve Longerbeam 	/* v4l2_ctrl_lock() locks our own mutex */
334519a81c14SSteve Longerbeam 
3346bce93b82SJacopo Mondi 	switch (ctrl->id) {
3347bce93b82SJacopo Mondi 	case V4L2_CID_VBLANK:
3348bce93b82SJacopo Mondi 		/* Update the exposure range to the newly programmed vblank. */
3349bce93b82SJacopo Mondi 		timings = ov5640_timings(sensor, mode);
3350bce93b82SJacopo Mondi 		exp_max = mode->height + ctrl->val - 4;
3351bce93b82SJacopo Mondi 		__v4l2_ctrl_modify_range(sensor->ctrls.exposure,
3352bce93b82SJacopo Mondi 					 sensor->ctrls.exposure->minimum,
3353bce93b82SJacopo Mondi 					 exp_max, sensor->ctrls.exposure->step,
3354bce93b82SJacopo Mondi 					 timings->vblank_def);
3355bce93b82SJacopo Mondi 		break;
3356bce93b82SJacopo Mondi 	}
3357bce93b82SJacopo Mondi 
335819a81c14SSteve Longerbeam 	/*
335919a81c14SSteve Longerbeam 	 * If the device is not powered up by the host driver do
336019a81c14SSteve Longerbeam 	 * not apply any controls to H/W at this time. Instead
336119a81c14SSteve Longerbeam 	 * the controls will be restored right after power-up.
336219a81c14SSteve Longerbeam 	 */
336319a81c14SSteve Longerbeam 	if (sensor->power_count == 0)
336419a81c14SSteve Longerbeam 		return 0;
336519a81c14SSteve Longerbeam 
336619a81c14SSteve Longerbeam 	switch (ctrl->id) {
336719a81c14SSteve Longerbeam 	case V4L2_CID_AUTOGAIN:
336819a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_gain(sensor, ctrl->val);
336919a81c14SSteve Longerbeam 		break;
337019a81c14SSteve Longerbeam 	case V4L2_CID_EXPOSURE_AUTO:
337119a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_exposure(sensor, ctrl->val);
337219a81c14SSteve Longerbeam 		break;
337319a81c14SSteve Longerbeam 	case V4L2_CID_AUTO_WHITE_BALANCE:
337419a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_white_balance(sensor, ctrl->val);
337519a81c14SSteve Longerbeam 		break;
337619a81c14SSteve Longerbeam 	case V4L2_CID_HUE:
337719a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_hue(sensor, ctrl->val);
337819a81c14SSteve Longerbeam 		break;
337919a81c14SSteve Longerbeam 	case V4L2_CID_CONTRAST:
338019a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_contrast(sensor, ctrl->val);
338119a81c14SSteve Longerbeam 		break;
338219a81c14SSteve Longerbeam 	case V4L2_CID_SATURATION:
338319a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_saturation(sensor, ctrl->val);
338419a81c14SSteve Longerbeam 		break;
338519a81c14SSteve Longerbeam 	case V4L2_CID_TEST_PATTERN:
338619a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_test_pattern(sensor, ctrl->val);
338719a81c14SSteve Longerbeam 		break;
33881068fecaSMylène Josserand 	case V4L2_CID_POWER_LINE_FREQUENCY:
33891068fecaSMylène Josserand 		ret = ov5640_set_ctrl_light_freq(sensor, ctrl->val);
33901068fecaSMylène Josserand 		break;
3391ce85705aSHugues Fruchet 	case V4L2_CID_HFLIP:
3392ce85705aSHugues Fruchet 		ret = ov5640_set_ctrl_hflip(sensor, ctrl->val);
3393ce85705aSHugues Fruchet 		break;
3394ce85705aSHugues Fruchet 	case V4L2_CID_VFLIP:
3395ce85705aSHugues Fruchet 		ret = ov5640_set_ctrl_vflip(sensor, ctrl->val);
3396ce85705aSHugues Fruchet 		break;
3397bce93b82SJacopo Mondi 	case V4L2_CID_VBLANK:
3398bce93b82SJacopo Mondi 		ret = ov5640_set_ctrl_vblank(sensor, ctrl->val);
3399bce93b82SJacopo Mondi 		break;
340019a81c14SSteve Longerbeam 	default:
340119a81c14SSteve Longerbeam 		ret = -EINVAL;
340219a81c14SSteve Longerbeam 		break;
340319a81c14SSteve Longerbeam 	}
340419a81c14SSteve Longerbeam 
340519a81c14SSteve Longerbeam 	return ret;
340619a81c14SSteve Longerbeam }
340719a81c14SSteve Longerbeam 
340819a81c14SSteve Longerbeam static const struct v4l2_ctrl_ops ov5640_ctrl_ops = {
340919a81c14SSteve Longerbeam 	.g_volatile_ctrl = ov5640_g_volatile_ctrl,
341019a81c14SSteve Longerbeam 	.s_ctrl = ov5640_s_ctrl,
341119a81c14SSteve Longerbeam };
341219a81c14SSteve Longerbeam 
341319a81c14SSteve Longerbeam static int ov5640_init_controls(struct ov5640_dev *sensor)
341419a81c14SSteve Longerbeam {
341522845bf2SJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
341619a81c14SSteve Longerbeam 	const struct v4l2_ctrl_ops *ops = &ov5640_ctrl_ops;
341719a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
341819a81c14SSteve Longerbeam 	struct v4l2_ctrl_handler *hdl = &ctrls->handler;
34191066fc1cSJacopo Mondi 	struct v4l2_fwnode_device_properties props;
342032979f67SJacopo Mondi 	const struct ov5640_timings *timings;
3421bce93b82SJacopo Mondi 	unsigned int max_vblank;
342232979f67SJacopo Mondi 	unsigned int hblank;
342319a81c14SSteve Longerbeam 	int ret;
342419a81c14SSteve Longerbeam 
342519a81c14SSteve Longerbeam 	v4l2_ctrl_handler_init(hdl, 32);
342619a81c14SSteve Longerbeam 
342719a81c14SSteve Longerbeam 	/* we can use our own mutex for the ctrl lock */
342819a81c14SSteve Longerbeam 	hdl->lock = &sensor->lock;
342919a81c14SSteve Longerbeam 
3430cc196e48SBenoit Parrot 	/* Clock related controls */
3431cc196e48SBenoit Parrot 	ctrls->pixel_rate = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE,
343222845bf2SJacopo Mondi 			      ov5640_pixel_rates[OV5640_NUM_PIXEL_RATES - 1],
343322845bf2SJacopo Mondi 			      ov5640_pixel_rates[0], 1,
343422845bf2SJacopo Mondi 			      ov5640_pixel_rates[mode->pixel_rate]);
3435cc196e48SBenoit Parrot 
34367a3b8d4bSJacopo Mondi 	ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops,
34377a3b8d4bSJacopo Mondi 					V4L2_CID_LINK_FREQ,
34387a3b8d4bSJacopo Mondi 					ARRAY_SIZE(ov5640_csi2_link_freqs) - 1,
34397a3b8d4bSJacopo Mondi 					OV5640_DEFAULT_LINK_FREQ,
34407a3b8d4bSJacopo Mondi 					ov5640_csi2_link_freqs);
34417a3b8d4bSJacopo Mondi 
344232979f67SJacopo Mondi 	timings = ov5640_timings(sensor, mode);
344332979f67SJacopo Mondi 	hblank = timings->htot - mode->width;
344432979f67SJacopo Mondi 	ctrls->hblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HBLANK, hblank,
344532979f67SJacopo Mondi 					  hblank, 1, hblank);
344632979f67SJacopo Mondi 
3447bce93b82SJacopo Mondi 	max_vblank = OV5640_MAX_VTS - mode->height;
3448bce93b82SJacopo Mondi 	ctrls->vblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VBLANK,
3449bce93b82SJacopo Mondi 					  OV5640_MIN_VBLANK, max_vblank,
3450bce93b82SJacopo Mondi 					  1, timings->vblank_def);
3451bce93b82SJacopo Mondi 
345219a81c14SSteve Longerbeam 	/* Auto/manual white balance */
345319a81c14SSteve Longerbeam 	ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops,
345419a81c14SSteve Longerbeam 					   V4L2_CID_AUTO_WHITE_BALANCE,
345519a81c14SSteve Longerbeam 					   0, 1, 1, 1);
345619a81c14SSteve Longerbeam 	ctrls->blue_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BLUE_BALANCE,
345719a81c14SSteve Longerbeam 						0, 4095, 1, 0);
345819a81c14SSteve Longerbeam 	ctrls->red_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_RED_BALANCE,
345919a81c14SSteve Longerbeam 					       0, 4095, 1, 0);
346019a81c14SSteve Longerbeam 	/* Auto/manual exposure */
346119a81c14SSteve Longerbeam 	ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops,
346219a81c14SSteve Longerbeam 						 V4L2_CID_EXPOSURE_AUTO,
346319a81c14SSteve Longerbeam 						 V4L2_EXPOSURE_MANUAL, 0,
346419a81c14SSteve Longerbeam 						 V4L2_EXPOSURE_AUTO);
346519a81c14SSteve Longerbeam 	ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
346619a81c14SSteve Longerbeam 					    0, 65535, 1, 0);
346719a81c14SSteve Longerbeam 	/* Auto/manual gain */
346819a81c14SSteve Longerbeam 	ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN,
346919a81c14SSteve Longerbeam 					     0, 1, 1, 1);
347019a81c14SSteve Longerbeam 	ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN,
347119a81c14SSteve Longerbeam 					0, 1023, 1, 0);
347219a81c14SSteve Longerbeam 
347319a81c14SSteve Longerbeam 	ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION,
347419a81c14SSteve Longerbeam 					      0, 255, 1, 64);
347519a81c14SSteve Longerbeam 	ctrls->hue = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HUE,
347619a81c14SSteve Longerbeam 				       0, 359, 1, 0);
347719a81c14SSteve Longerbeam 	ctrls->contrast = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST,
347819a81c14SSteve Longerbeam 					    0, 255, 1, 0);
347919a81c14SSteve Longerbeam 	ctrls->test_pattern =
348019a81c14SSteve Longerbeam 		v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN,
348119a81c14SSteve Longerbeam 					     ARRAY_SIZE(test_pattern_menu) - 1,
348219a81c14SSteve Longerbeam 					     0, 0, test_pattern_menu);
3483ce85705aSHugues Fruchet 	ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP,
3484ce85705aSHugues Fruchet 					 0, 1, 1, 0);
3485ce85705aSHugues Fruchet 	ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP,
3486ce85705aSHugues Fruchet 					 0, 1, 1, 0);
348719a81c14SSteve Longerbeam 
34881068fecaSMylène Josserand 	ctrls->light_freq =
34891068fecaSMylène Josserand 		v4l2_ctrl_new_std_menu(hdl, ops,
34901068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY,
34911068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
34921068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
34931068fecaSMylène Josserand 
349419a81c14SSteve Longerbeam 	if (hdl->error) {
349519a81c14SSteve Longerbeam 		ret = hdl->error;
349619a81c14SSteve Longerbeam 		goto free_ctrls;
349719a81c14SSteve Longerbeam 	}
349819a81c14SSteve Longerbeam 
34991066fc1cSJacopo Mondi 	ret = v4l2_fwnode_device_parse(&sensor->i2c_client->dev, &props);
35001066fc1cSJacopo Mondi 	if (ret)
35011066fc1cSJacopo Mondi 		goto free_ctrls;
35021066fc1cSJacopo Mondi 
35031066fc1cSJacopo Mondi 	if (props.rotation == 180)
35041066fc1cSJacopo Mondi 		sensor->upside_down = true;
35051066fc1cSJacopo Mondi 
35061066fc1cSJacopo Mondi 	ret = v4l2_ctrl_new_fwnode_properties(hdl, ops, &props);
35071066fc1cSJacopo Mondi 	if (ret)
35081066fc1cSJacopo Mondi 		goto free_ctrls;
35091066fc1cSJacopo Mondi 
3510cc196e48SBenoit Parrot 	ctrls->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY;
35117a3b8d4bSJacopo Mondi 	ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
351232979f67SJacopo Mondi 	ctrls->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
351319a81c14SSteve Longerbeam 	ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE;
351419a81c14SSteve Longerbeam 	ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE;
351519a81c14SSteve Longerbeam 
351619a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false);
351719a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(2, &ctrls->auto_gain, 0, true);
351819a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(2, &ctrls->auto_exp, 1, true);
351919a81c14SSteve Longerbeam 
352019a81c14SSteve Longerbeam 	sensor->sd.ctrl_handler = hdl;
352119a81c14SSteve Longerbeam 	return 0;
352219a81c14SSteve Longerbeam 
352319a81c14SSteve Longerbeam free_ctrls:
352419a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(hdl);
352519a81c14SSteve Longerbeam 	return ret;
352619a81c14SSteve Longerbeam }
352719a81c14SSteve Longerbeam 
352819a81c14SSteve Longerbeam static int ov5640_enum_frame_size(struct v4l2_subdev *sd,
35290d346d2aSTomi Valkeinen 				  struct v4l2_subdev_state *sd_state,
353019a81c14SSteve Longerbeam 				  struct v4l2_subdev_frame_size_enum *fse)
353119a81c14SSteve Longerbeam {
3532a89f14bbSJacopo Mondi 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
3533a89f14bbSJacopo Mondi 	u32 bpp = ov5640_code_to_bpp(sensor, fse->code);
35347dcb3a2fSJacopo Mondi 	unsigned int index = fse->index;
35357dcb3a2fSJacopo Mondi 
353619a81c14SSteve Longerbeam 	if (fse->pad != 0)
353719a81c14SSteve Longerbeam 		return -EINVAL;
35387dcb3a2fSJacopo Mondi 	if (!bpp)
353919a81c14SSteve Longerbeam 		return -EINVAL;
354019a81c14SSteve Longerbeam 
35417dcb3a2fSJacopo Mondi 	/* Only low-resolution modes are supported for 24bpp formats. */
35427dcb3a2fSJacopo Mondi 	if (bpp == 24 && index >= OV5640_MODE_720P_1280_720)
35437dcb3a2fSJacopo Mondi 		return -EINVAL;
35447dcb3a2fSJacopo Mondi 
35457dcb3a2fSJacopo Mondi 	/* FIXME: Low resolution modes don't work in 8bpp formats. */
35467dcb3a2fSJacopo Mondi 	if (bpp == 8)
35477dcb3a2fSJacopo Mondi 		index += OV5640_MODE_720P_1280_720;
35487dcb3a2fSJacopo Mondi 
35497dcb3a2fSJacopo Mondi 	if (index >= OV5640_NUM_MODES)
35507dcb3a2fSJacopo Mondi 		return -EINVAL;
35517dcb3a2fSJacopo Mondi 
35527dcb3a2fSJacopo Mondi 	fse->min_width = ov5640_mode_data[index].width;
355341d8d7f5SHugues Fruchet 	fse->max_width = fse->min_width;
35547dcb3a2fSJacopo Mondi 	fse->min_height = ov5640_mode_data[index].height;
355541d8d7f5SHugues Fruchet 	fse->max_height = fse->min_height;
355619a81c14SSteve Longerbeam 
355719a81c14SSteve Longerbeam 	return 0;
355819a81c14SSteve Longerbeam }
355919a81c14SSteve Longerbeam 
356019a81c14SSteve Longerbeam static int ov5640_enum_frame_interval(
356119a81c14SSteve Longerbeam 	struct v4l2_subdev *sd,
35620d346d2aSTomi Valkeinen 	struct v4l2_subdev_state *sd_state,
356319a81c14SSteve Longerbeam 	struct v4l2_subdev_frame_interval_enum *fie)
356419a81c14SSteve Longerbeam {
356519a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
356619a81c14SSteve Longerbeam 	struct v4l2_fract tpf;
356719a81c14SSteve Longerbeam 	int ret;
356819a81c14SSteve Longerbeam 
356919a81c14SSteve Longerbeam 	if (fie->pad != 0)
357019a81c14SSteve Longerbeam 		return -EINVAL;
357119a81c14SSteve Longerbeam 	if (fie->index >= OV5640_NUM_FRAMERATES)
357219a81c14SSteve Longerbeam 		return -EINVAL;
357319a81c14SSteve Longerbeam 
357419a81c14SSteve Longerbeam 	tpf.numerator = 1;
357519a81c14SSteve Longerbeam 	tpf.denominator = ov5640_framerates[fie->index];
357619a81c14SSteve Longerbeam 
357719a81c14SSteve Longerbeam 	ret = ov5640_try_frame_interval(sensor, &tpf,
357819a81c14SSteve Longerbeam 					fie->width, fie->height);
357919a81c14SSteve Longerbeam 	if (ret < 0)
358019a81c14SSteve Longerbeam 		return -EINVAL;
358119a81c14SSteve Longerbeam 
358219a81c14SSteve Longerbeam 	fie->interval = tpf;
358319a81c14SSteve Longerbeam 	return 0;
358419a81c14SSteve Longerbeam }
358519a81c14SSteve Longerbeam 
358619a81c14SSteve Longerbeam static int ov5640_g_frame_interval(struct v4l2_subdev *sd,
358719a81c14SSteve Longerbeam 				   struct v4l2_subdev_frame_interval *fi)
358819a81c14SSteve Longerbeam {
358919a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
359019a81c14SSteve Longerbeam 
359119a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
359219a81c14SSteve Longerbeam 	fi->interval = sensor->frame_interval;
359319a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
359419a81c14SSteve Longerbeam 
359519a81c14SSteve Longerbeam 	return 0;
359619a81c14SSteve Longerbeam }
359719a81c14SSteve Longerbeam 
359819a81c14SSteve Longerbeam static int ov5640_s_frame_interval(struct v4l2_subdev *sd,
359919a81c14SSteve Longerbeam 				   struct v4l2_subdev_frame_interval *fi)
360019a81c14SSteve Longerbeam {
360119a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
360219a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
360319a81c14SSteve Longerbeam 	int frame_rate, ret = 0;
360419a81c14SSteve Longerbeam 
360519a81c14SSteve Longerbeam 	if (fi->pad != 0)
360619a81c14SSteve Longerbeam 		return -EINVAL;
360719a81c14SSteve Longerbeam 
360819a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
360919a81c14SSteve Longerbeam 
361019a81c14SSteve Longerbeam 	if (sensor->streaming) {
361119a81c14SSteve Longerbeam 		ret = -EBUSY;
361219a81c14SSteve Longerbeam 		goto out;
361319a81c14SSteve Longerbeam 	}
361419a81c14SSteve Longerbeam 
361519a81c14SSteve Longerbeam 	mode = sensor->current_mode;
361619a81c14SSteve Longerbeam 
361719a81c14SSteve Longerbeam 	frame_rate = ov5640_try_frame_interval(sensor, &fi->interval,
36185113d5b3SJacopo Mondi 					       mode->width,
36195113d5b3SJacopo Mondi 					       mode->height);
3620e823fb16SMaxime Ripard 	if (frame_rate < 0) {
3621e823fb16SMaxime Ripard 		/* Always return a valid frame interval value */
3622e823fb16SMaxime Ripard 		fi->interval = sensor->frame_interval;
3623e823fb16SMaxime Ripard 		goto out;
3624e823fb16SMaxime Ripard 	}
362519a81c14SSteve Longerbeam 
3626b6ae5022SJacopo Mondi 	mode = ov5640_find_mode(sensor, mode->width, mode->height, true);
36273c4a7372SHugues Fruchet 	if (!mode) {
36283c4a7372SHugues Fruchet 		ret = -EINVAL;
36293c4a7372SHugues Fruchet 		goto out;
36303c4a7372SHugues Fruchet 	}
36313c4a7372SHugues Fruchet 
3632b6ae5022SJacopo Mondi 	if (ov5640_framerates[frame_rate] > ov5640_framerates[mode->max_fps]) {
3633b6ae5022SJacopo Mondi 		ret = -EINVAL;
3634b6ae5022SJacopo Mondi 		goto out;
3635b6ae5022SJacopo Mondi 	}
3636b6ae5022SJacopo Mondi 
36370929983eSHugues Fruchet 	if (mode != sensor->current_mode ||
36380929983eSHugues Fruchet 	    frame_rate != sensor->current_fr) {
36390929983eSHugues Fruchet 		sensor->current_fr = frame_rate;
36400929983eSHugues Fruchet 		sensor->frame_interval = fi->interval;
36413c4a7372SHugues Fruchet 		sensor->current_mode = mode;
364219a81c14SSteve Longerbeam 		sensor->pending_mode_change = true;
3643cc196e48SBenoit Parrot 
364419f2e3e6SHugues Fruchet 		ov5640_update_pixel_rate(sensor);
36456949d864SHugues Fruchet 	}
364619a81c14SSteve Longerbeam out:
364719a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
364819a81c14SSteve Longerbeam 	return ret;
364919a81c14SSteve Longerbeam }
365019a81c14SSteve Longerbeam 
365119a81c14SSteve Longerbeam static int ov5640_enum_mbus_code(struct v4l2_subdev *sd,
36520d346d2aSTomi Valkeinen 				 struct v4l2_subdev_state *sd_state,
365319a81c14SSteve Longerbeam 				 struct v4l2_subdev_mbus_code_enum *code)
365419a81c14SSteve Longerbeam {
3655a89f14bbSJacopo Mondi 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
3656a89f14bbSJacopo Mondi 	const struct ov5640_pixfmt *formats;
3657a89f14bbSJacopo Mondi 	unsigned int num_formats;
3658a89f14bbSJacopo Mondi 
3659a89f14bbSJacopo Mondi 	if (ov5640_is_csi2(sensor)) {
3660a89f14bbSJacopo Mondi 		formats = ov5640_csi2_formats;
3661a89f14bbSJacopo Mondi 		num_formats = ARRAY_SIZE(ov5640_csi2_formats) - 1;
3662a89f14bbSJacopo Mondi 	} else {
3663a89f14bbSJacopo Mondi 		formats = ov5640_dvp_formats;
3664a89f14bbSJacopo Mondi 		num_formats = ARRAY_SIZE(ov5640_dvp_formats) - 1;
3665a89f14bbSJacopo Mondi 	}
3666a89f14bbSJacopo Mondi 
3667a89f14bbSJacopo Mondi 	if (code->index >= num_formats)
366819a81c14SSteve Longerbeam 		return -EINVAL;
366919a81c14SSteve Longerbeam 
3670a89f14bbSJacopo Mondi 	code->code = formats[code->index].code;
3671a89f14bbSJacopo Mondi 
367219a81c14SSteve Longerbeam 	return 0;
367319a81c14SSteve Longerbeam }
367419a81c14SSteve Longerbeam 
367519a81c14SSteve Longerbeam static int ov5640_s_stream(struct v4l2_subdev *sd, int enable)
367619a81c14SSteve Longerbeam {
367719a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
367819a81c14SSteve Longerbeam 	int ret = 0;
367919a81c14SSteve Longerbeam 
368019a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
368119a81c14SSteve Longerbeam 
368219a81c14SSteve Longerbeam 	if (sensor->streaming == !enable) {
368319a81c14SSteve Longerbeam 		if (enable && sensor->pending_mode_change) {
3684985cdcb0SHugues Fruchet 			ret = ov5640_set_mode(sensor);
368519a81c14SSteve Longerbeam 			if (ret)
368619a81c14SSteve Longerbeam 				goto out;
3687fb98e29fSHugues Fruchet 		}
3688e3ee691dSHugues Fruchet 
3689fb98e29fSHugues Fruchet 		if (enable && sensor->pending_fmt_change) {
3690e3ee691dSHugues Fruchet 			ret = ov5640_set_framefmt(sensor, &sensor->fmt);
3691e3ee691dSHugues Fruchet 			if (ret)
3692e3ee691dSHugues Fruchet 				goto out;
3693fb98e29fSHugues Fruchet 			sensor->pending_fmt_change = false;
369419a81c14SSteve Longerbeam 		}
369519a81c14SSteve Longerbeam 
36968e823f5cSJacopo Mondi 		if (ov5640_is_csi2(sensor))
3697f22996dbSHugues Fruchet 			ret = ov5640_set_stream_mipi(sensor, enable);
3698f22996dbSHugues Fruchet 		else
3699f22996dbSHugues Fruchet 			ret = ov5640_set_stream_dvp(sensor, enable);
3700f22996dbSHugues Fruchet 
370119a81c14SSteve Longerbeam 		if (!ret)
370219a81c14SSteve Longerbeam 			sensor->streaming = enable;
370319a81c14SSteve Longerbeam 	}
370419a81c14SSteve Longerbeam out:
370519a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
370619a81c14SSteve Longerbeam 	return ret;
370719a81c14SSteve Longerbeam }
370819a81c14SSteve Longerbeam 
370990b0f355SJacopo Mondi static int ov5640_init_cfg(struct v4l2_subdev *sd,
371090b0f355SJacopo Mondi 			   struct v4l2_subdev_state *state)
371190b0f355SJacopo Mondi {
371290b0f355SJacopo Mondi 	struct v4l2_mbus_framefmt *fmt =
371390b0f355SJacopo Mondi 				v4l2_subdev_get_try_format(sd, state, 0);
371466ed85ebSJacopo Mondi 	struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, state, 0);
371590b0f355SJacopo Mondi 
371690b0f355SJacopo Mondi 	*fmt = ov5640_default_fmt;
371790b0f355SJacopo Mondi 
371866ed85ebSJacopo Mondi 	crop->left = OV5640_PIXEL_ARRAY_LEFT;
371966ed85ebSJacopo Mondi 	crop->top = OV5640_PIXEL_ARRAY_TOP;
372066ed85ebSJacopo Mondi 	crop->width = OV5640_PIXEL_ARRAY_WIDTH;
372166ed85ebSJacopo Mondi 	crop->height = OV5640_PIXEL_ARRAY_HEIGHT;
372266ed85ebSJacopo Mondi 
372390b0f355SJacopo Mondi 	return 0;
372490b0f355SJacopo Mondi }
372590b0f355SJacopo Mondi 
372619a81c14SSteve Longerbeam static const struct v4l2_subdev_core_ops ov5640_core_ops = {
372719a81c14SSteve Longerbeam 	.s_power = ov5640_s_power,
37282d18fbc5SAkinobu Mita 	.log_status = v4l2_ctrl_subdev_log_status,
37292d18fbc5SAkinobu Mita 	.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
37302d18fbc5SAkinobu Mita 	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
373119a81c14SSteve Longerbeam };
373219a81c14SSteve Longerbeam 
373319a81c14SSteve Longerbeam static const struct v4l2_subdev_video_ops ov5640_video_ops = {
373419a81c14SSteve Longerbeam 	.g_frame_interval = ov5640_g_frame_interval,
373519a81c14SSteve Longerbeam 	.s_frame_interval = ov5640_s_frame_interval,
373619a81c14SSteve Longerbeam 	.s_stream = ov5640_s_stream,
373719a81c14SSteve Longerbeam };
373819a81c14SSteve Longerbeam 
373919a81c14SSteve Longerbeam static const struct v4l2_subdev_pad_ops ov5640_pad_ops = {
374090b0f355SJacopo Mondi 	.init_cfg = ov5640_init_cfg,
374119a81c14SSteve Longerbeam 	.enum_mbus_code = ov5640_enum_mbus_code,
374219a81c14SSteve Longerbeam 	.get_fmt = ov5640_get_fmt,
374319a81c14SSteve Longerbeam 	.set_fmt = ov5640_set_fmt,
374466ed85ebSJacopo Mondi 	.get_selection = ov5640_get_selection,
374519a81c14SSteve Longerbeam 	.enum_frame_size = ov5640_enum_frame_size,
374619a81c14SSteve Longerbeam 	.enum_frame_interval = ov5640_enum_frame_interval,
374719a81c14SSteve Longerbeam };
374819a81c14SSteve Longerbeam 
374919a81c14SSteve Longerbeam static const struct v4l2_subdev_ops ov5640_subdev_ops = {
375019a81c14SSteve Longerbeam 	.core = &ov5640_core_ops,
375119a81c14SSteve Longerbeam 	.video = &ov5640_video_ops,
375219a81c14SSteve Longerbeam 	.pad = &ov5640_pad_ops,
375319a81c14SSteve Longerbeam };
375419a81c14SSteve Longerbeam 
375519a81c14SSteve Longerbeam static int ov5640_get_regulators(struct ov5640_dev *sensor)
375619a81c14SSteve Longerbeam {
375719a81c14SSteve Longerbeam 	int i;
375819a81c14SSteve Longerbeam 
375919a81c14SSteve Longerbeam 	for (i = 0; i < OV5640_NUM_SUPPLIES; i++)
376019a81c14SSteve Longerbeam 		sensor->supplies[i].supply = ov5640_supply_name[i];
376119a81c14SSteve Longerbeam 
376219a81c14SSteve Longerbeam 	return devm_regulator_bulk_get(&sensor->i2c_client->dev,
376319a81c14SSteve Longerbeam 				       OV5640_NUM_SUPPLIES,
376419a81c14SSteve Longerbeam 				       sensor->supplies);
376519a81c14SSteve Longerbeam }
376619a81c14SSteve Longerbeam 
37670f7acb52SHugues Fruchet static int ov5640_check_chip_id(struct ov5640_dev *sensor)
37680f7acb52SHugues Fruchet {
37690f7acb52SHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
37700f7acb52SHugues Fruchet 	int ret = 0;
37710f7acb52SHugues Fruchet 	u16 chip_id;
37720f7acb52SHugues Fruchet 
37730f7acb52SHugues Fruchet 	ret = ov5640_set_power_on(sensor);
37740f7acb52SHugues Fruchet 	if (ret)
37750f7acb52SHugues Fruchet 		return ret;
37760f7acb52SHugues Fruchet 
37770f7acb52SHugues Fruchet 	ret = ov5640_read_reg16(sensor, OV5640_REG_CHIP_ID, &chip_id);
37780f7acb52SHugues Fruchet 	if (ret) {
37790f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to read chip identifier\n",
37800f7acb52SHugues Fruchet 			__func__);
37810f7acb52SHugues Fruchet 		goto power_off;
37820f7acb52SHugues Fruchet 	}
37830f7acb52SHugues Fruchet 
37840f7acb52SHugues Fruchet 	if (chip_id != 0x5640) {
37850f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: wrong chip identifier, expected 0x5640, got 0x%x\n",
37860f7acb52SHugues Fruchet 			__func__, chip_id);
37870f7acb52SHugues Fruchet 		ret = -ENXIO;
37880f7acb52SHugues Fruchet 	}
37890f7acb52SHugues Fruchet 
37900f7acb52SHugues Fruchet power_off:
37910f7acb52SHugues Fruchet 	ov5640_set_power_off(sensor);
37920f7acb52SHugues Fruchet 	return ret;
37930f7acb52SHugues Fruchet }
37940f7acb52SHugues Fruchet 
3795e6714993SKieran Bingham static int ov5640_probe(struct i2c_client *client)
379619a81c14SSteve Longerbeam {
379719a81c14SSteve Longerbeam 	struct device *dev = &client->dev;
379819a81c14SSteve Longerbeam 	struct fwnode_handle *endpoint;
379919a81c14SSteve Longerbeam 	struct ov5640_dev *sensor;
380019a81c14SSteve Longerbeam 	int ret;
380119a81c14SSteve Longerbeam 
380219a81c14SSteve Longerbeam 	sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
380319a81c14SSteve Longerbeam 	if (!sensor)
380419a81c14SSteve Longerbeam 		return -ENOMEM;
380519a81c14SSteve Longerbeam 
380619a81c14SSteve Longerbeam 	sensor->i2c_client = client;
3807fb98e29fSHugues Fruchet 
3808fb98e29fSHugues Fruchet 	/*
3809fb98e29fSHugues Fruchet 	 * default init sequence initialize sensor to
3810fb98e29fSHugues Fruchet 	 * YUV422 UYVY VGA@30fps
3811fb98e29fSHugues Fruchet 	 */
381290b0f355SJacopo Mondi 	sensor->fmt = ov5640_default_fmt;
381319a81c14SSteve Longerbeam 	sensor->frame_interval.numerator = 1;
381419a81c14SSteve Longerbeam 	sensor->frame_interval.denominator = ov5640_framerates[OV5640_30_FPS];
381519a81c14SSteve Longerbeam 	sensor->current_fr = OV5640_30_FPS;
381619a81c14SSteve Longerbeam 	sensor->current_mode =
3817086c25f8SMaxime Ripard 		&ov5640_mode_data[OV5640_MODE_VGA_640_480];
3818985cdcb0SHugues Fruchet 	sensor->last_mode = sensor->current_mode;
38193c28588fSJacopo Mondi 	sensor->current_link_freq = OV5640_DEFAULT_LINK_FREQ;
382019a81c14SSteve Longerbeam 
382119a81c14SSteve Longerbeam 	sensor->ae_target = 52;
382219a81c14SSteve Longerbeam 
3823ce96bcf5SSakari Ailus 	endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev),
3824ce96bcf5SSakari Ailus 						  NULL);
382519a81c14SSteve Longerbeam 	if (!endpoint) {
382619a81c14SSteve Longerbeam 		dev_err(dev, "endpoint node not found\n");
382719a81c14SSteve Longerbeam 		return -EINVAL;
382819a81c14SSteve Longerbeam 	}
382919a81c14SSteve Longerbeam 
383019a81c14SSteve Longerbeam 	ret = v4l2_fwnode_endpoint_parse(endpoint, &sensor->ep);
383119a81c14SSteve Longerbeam 	fwnode_handle_put(endpoint);
383219a81c14SSteve Longerbeam 	if (ret) {
383319a81c14SSteve Longerbeam 		dev_err(dev, "Could not parse endpoint\n");
383419a81c14SSteve Longerbeam 		return ret;
383519a81c14SSteve Longerbeam 	}
383619a81c14SSteve Longerbeam 
38372c61e48dSLad Prabhakar 	if (sensor->ep.bus_type != V4L2_MBUS_PARALLEL &&
38382c61e48dSLad Prabhakar 	    sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY &&
38392c61e48dSLad Prabhakar 	    sensor->ep.bus_type != V4L2_MBUS_BT656) {
38402c61e48dSLad Prabhakar 		dev_err(dev, "Unsupported bus type %d\n", sensor->ep.bus_type);
38412c61e48dSLad Prabhakar 		return -EINVAL;
38422c61e48dSLad Prabhakar 	}
38432c61e48dSLad Prabhakar 
384419a81c14SSteve Longerbeam 	/* get system clock (xclk) */
384519a81c14SSteve Longerbeam 	sensor->xclk = devm_clk_get(dev, "xclk");
384619a81c14SSteve Longerbeam 	if (IS_ERR(sensor->xclk)) {
384719a81c14SSteve Longerbeam 		dev_err(dev, "failed to get xclk\n");
384819a81c14SSteve Longerbeam 		return PTR_ERR(sensor->xclk);
384919a81c14SSteve Longerbeam 	}
385019a81c14SSteve Longerbeam 
385119a81c14SSteve Longerbeam 	sensor->xclk_freq = clk_get_rate(sensor->xclk);
385219a81c14SSteve Longerbeam 	if (sensor->xclk_freq < OV5640_XCLK_MIN ||
385319a81c14SSteve Longerbeam 	    sensor->xclk_freq > OV5640_XCLK_MAX) {
385419a81c14SSteve Longerbeam 		dev_err(dev, "xclk frequency out of range: %d Hz\n",
385519a81c14SSteve Longerbeam 			sensor->xclk_freq);
385619a81c14SSteve Longerbeam 		return -EINVAL;
385719a81c14SSteve Longerbeam 	}
385819a81c14SSteve Longerbeam 
385919a81c14SSteve Longerbeam 	/* request optional power down pin */
386019a81c14SSteve Longerbeam 	sensor->pwdn_gpio = devm_gpiod_get_optional(dev, "powerdown",
386119a81c14SSteve Longerbeam 						    GPIOD_OUT_HIGH);
38628791a102SFabio Estevam 	if (IS_ERR(sensor->pwdn_gpio))
38638791a102SFabio Estevam 		return PTR_ERR(sensor->pwdn_gpio);
38648791a102SFabio Estevam 
386519a81c14SSteve Longerbeam 	/* request optional reset pin */
386619a81c14SSteve Longerbeam 	sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset",
386719a81c14SSteve Longerbeam 						     GPIOD_OUT_HIGH);
38688791a102SFabio Estevam 	if (IS_ERR(sensor->reset_gpio))
38698791a102SFabio Estevam 		return PTR_ERR(sensor->reset_gpio);
387019a81c14SSteve Longerbeam 
387119a81c14SSteve Longerbeam 	v4l2_i2c_subdev_init(&sensor->sd, client, &ov5640_subdev_ops);
387219a81c14SSteve Longerbeam 
38732d18fbc5SAkinobu Mita 	sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
38742d18fbc5SAkinobu Mita 			    V4L2_SUBDEV_FL_HAS_EVENTS;
387519a81c14SSteve Longerbeam 	sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
387619a81c14SSteve Longerbeam 	sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
387719a81c14SSteve Longerbeam 	ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
387819a81c14SSteve Longerbeam 	if (ret)
387919a81c14SSteve Longerbeam 		return ret;
388019a81c14SSteve Longerbeam 
388119a81c14SSteve Longerbeam 	ret = ov5640_get_regulators(sensor);
388219a81c14SSteve Longerbeam 	if (ret)
388319a81c14SSteve Longerbeam 		return ret;
388419a81c14SSteve Longerbeam 
388519a81c14SSteve Longerbeam 	mutex_init(&sensor->lock);
388619a81c14SSteve Longerbeam 
38870f7acb52SHugues Fruchet 	ret = ov5640_check_chip_id(sensor);
38880f7acb52SHugues Fruchet 	if (ret)
38890f7acb52SHugues Fruchet 		goto entity_cleanup;
38900f7acb52SHugues Fruchet 
389119a81c14SSteve Longerbeam 	ret = ov5640_init_controls(sensor);
389219a81c14SSteve Longerbeam 	if (ret)
389319a81c14SSteve Longerbeam 		goto entity_cleanup;
389419a81c14SSteve Longerbeam 
389515786f7bSSakari Ailus 	ret = v4l2_async_register_subdev_sensor(&sensor->sd);
389619a81c14SSteve Longerbeam 	if (ret)
389719a81c14SSteve Longerbeam 		goto free_ctrls;
389819a81c14SSteve Longerbeam 
389919a81c14SSteve Longerbeam 	return 0;
390019a81c14SSteve Longerbeam 
390119a81c14SSteve Longerbeam free_ctrls:
390219a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
390319a81c14SSteve Longerbeam entity_cleanup:
390419a81c14SSteve Longerbeam 	media_entity_cleanup(&sensor->sd.entity);
3905bfcba38dSTomi Valkeinen 	mutex_destroy(&sensor->lock);
390619a81c14SSteve Longerbeam 	return ret;
390719a81c14SSteve Longerbeam }
390819a81c14SSteve Longerbeam 
3909*ed5c2f5fSUwe Kleine-König static void ov5640_remove(struct i2c_client *client)
391019a81c14SSteve Longerbeam {
391119a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
391219a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
391319a81c14SSteve Longerbeam 
391419a81c14SSteve Longerbeam 	v4l2_async_unregister_subdev(&sensor->sd);
391519a81c14SSteve Longerbeam 	media_entity_cleanup(&sensor->sd.entity);
391619a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
3917bfcba38dSTomi Valkeinen 	mutex_destroy(&sensor->lock);
391819a81c14SSteve Longerbeam }
391919a81c14SSteve Longerbeam 
392019a81c14SSteve Longerbeam static const struct i2c_device_id ov5640_id[] = {
392119a81c14SSteve Longerbeam 	{"ov5640", 0},
392219a81c14SSteve Longerbeam 	{},
392319a81c14SSteve Longerbeam };
392419a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(i2c, ov5640_id);
392519a81c14SSteve Longerbeam 
392619a81c14SSteve Longerbeam static const struct of_device_id ov5640_dt_ids[] = {
392719a81c14SSteve Longerbeam 	{ .compatible = "ovti,ov5640" },
392819a81c14SSteve Longerbeam 	{ /* sentinel */ }
392919a81c14SSteve Longerbeam };
393019a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(of, ov5640_dt_ids);
393119a81c14SSteve Longerbeam 
393219a81c14SSteve Longerbeam static struct i2c_driver ov5640_i2c_driver = {
393319a81c14SSteve Longerbeam 	.driver = {
393419a81c14SSteve Longerbeam 		.name  = "ov5640",
393519a81c14SSteve Longerbeam 		.of_match_table	= ov5640_dt_ids,
393619a81c14SSteve Longerbeam 	},
393719a81c14SSteve Longerbeam 	.id_table = ov5640_id,
3938e6714993SKieran Bingham 	.probe_new = ov5640_probe,
393919a81c14SSteve Longerbeam 	.remove   = ov5640_remove,
394019a81c14SSteve Longerbeam };
394119a81c14SSteve Longerbeam 
394219a81c14SSteve Longerbeam module_i2c_driver(ov5640_i2c_driver);
394319a81c14SSteve Longerbeam 
394419a81c14SSteve Longerbeam MODULE_DESCRIPTION("OV5640 MIPI Camera Subdev Driver");
394519a81c14SSteve Longerbeam MODULE_LICENSE("GPL");
3946